@prnv/tuck 1.5.2 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -10
- package/dist/index.js +2100 -127
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ui/theme.ts","../src/ui/banner.ts","../src/ui/logger.ts","../src/ui/prompts.ts","../src/ui/spinner.ts","../src/ui/table.ts","../src/ui/progress.ts","../src/ui/index.ts","../src/constants.ts","../src/lib/paths.ts","../src/schemas/secrets.schema.ts","../src/schemas/config.schema.ts","../src/errors.ts","../src/lib/config.ts","../src/schemas/manifest.schema.ts","../src/lib/manifest.ts","../src/lib/git.ts","../src/lib/github.ts","../src/lib/detect.ts","../src/lib/files.ts","../src/lib/fileTracking.ts","../src/lib/backup.ts","../src/lib/hooks.ts","../src/commands/restore.ts","../src/lib/tuckignore.ts","../src/lib/secrets/patterns.ts","../src/lib/secrets/scanner.ts","../src/lib/secrets/store.ts","../src/lib/secrets/redactor.ts","../src/lib/secrets/external.ts","../src/lib/secrets/index.ts","../src/commands/secrets.ts","../src/commands/sync.ts","../src/index.ts","../src/commands/init.ts","../src/commands/add.ts","../src/lib/binary.ts","../src/commands/remove.ts","../src/commands/index.ts","../src/commands/push.ts","../src/commands/pull.ts","../src/commands/status.ts","../src/commands/list.ts","../src/commands/diff.ts","../src/commands/config.ts","../src/commands/apply.ts","../src/lib/timemachine.ts","../src/lib/merge.ts","../src/commands/undo.ts","../src/commands/scan.ts"],"sourcesContent":["/**\n * Design System for tuck CLI\n * Centralized design tokens, colors, icons, and helpers\n */\n\nimport chalk from 'chalk';\nimport figures from 'figures';\nimport logSymbols from 'log-symbols';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Layout Constants\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const TERMINAL_WIDTH = 100;\nexport const CONTENT_WIDTH = 80;\nexport const DIVIDER_WIDTH = 60;\nexport const INDENT = ' ';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Colors (semantic naming)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const colors = {\n // Brand\n brand: chalk.cyan,\n brandBold: chalk.bold.cyan,\n brandDim: chalk.dim.cyan,\n brandBg: chalk.bgCyan.black,\n\n // Status\n success: chalk.green,\n warning: chalk.yellow,\n error: chalk.red,\n info: chalk.blue,\n\n // Text\n muted: chalk.dim,\n bold: chalk.bold,\n highlight: chalk.bold.white,\n\n // Direct color aliases (for compatibility)\n cyan: chalk.cyan,\n green: chalk.green,\n yellow: chalk.yellow,\n red: chalk.red,\n blue: chalk.blue,\n dim: chalk.dim,\n white: chalk.white,\n};\n\n// Shorthand alias\nexport const c = colors;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Icons (with automatic Unicode fallbacks via figures)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const icons = {\n // Status icons (colored, from log-symbols)\n success: logSymbols.success,\n error: logSymbols.error,\n warning: logSymbols.warning,\n info: logSymbols.info,\n\n // Action icons (from figures - auto fallback)\n tick: figures.tick,\n cross: figures.cross,\n pointer: figures.pointer,\n arrowRight: figures.arrowRight,\n arrowDown: figures.arrowDown,\n arrowUp: figures.arrowUp,\n\n // Progress icons\n circle: figures.circle,\n circleFilled: figures.circleFilled,\n bullet: figures.bullet,\n ellipsis: figures.ellipsis,\n\n // File operations\n add: c.success(figures.tick),\n remove: c.error(figures.cross),\n modify: c.warning('~'),\n sync: c.brand(figures.arrowRight),\n\n // Tree/structure\n line: figures.line,\n corner: figures.lineDownRight,\n tee: figures.lineDownRightArc,\n\n // Category icons\n shell: '$',\n git: figures.star,\n editors: figures.pointer,\n terminal: '#',\n ssh: figures.warning,\n misc: figures.bullet,\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Category Configuration (icons + colors)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CategoryStyle {\n icon: string;\n color: typeof chalk;\n}\n\nexport const categoryStyles: Record<string, CategoryStyle> = {\n shell: { icon: '$', color: c.success },\n git: { icon: figures.star, color: c.warning },\n editors: { icon: figures.pointer, color: c.brand },\n terminal: { icon: '#', color: c.info },\n ssh: { icon: figures.warning, color: c.error },\n misc: { icon: figures.bullet, color: c.muted },\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Layout Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Create a horizontal divider line */\nexport const divider = (width = DIVIDER_WIDTH): string => c.muted('─'.repeat(width));\n\n/** Create indentation */\nexport const indent = (level = 1): string => INDENT.repeat(level);\n\n/** Print a blank line */\nexport const spacer = (): void => {\n console.log();\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Text Formatting Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Format a file path with brand color */\nexport const formatPath = (path: string): string => c.brand(path);\n\n/** Format a count with proper pluralization: \"3 files\" */\nexport const formatCount = (n: number, singular: string, plural?: string): string => {\n const word = n === 1 ? singular : plural || `${singular}s`;\n return `${c.bold(n.toString())} ${word}`;\n};\n\n/** Format a category with its icon */\nexport const formatCategory = (category: string): string => {\n const style = categoryStyles[category] || categoryStyles.misc;\n return `${style.color(style.icon)} ${category}`;\n};\n\n/** Format a status string with appropriate color */\nexport const formatStatus = (status: string): string => {\n switch (status) {\n case 'added':\n return c.success(status);\n case 'modified':\n return c.warning(status);\n case 'deleted':\n return c.error(status);\n default:\n return c.muted(status);\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Message Helpers (concise, consistent)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Format a hint message (dimmed, for secondary info) */\nexport const hint = (message: string): string => c.muted(message);\n\n/** Format a command suggestion */\nexport const cmd = (command: string): string => c.brand(`'${command}'`);\n\n/** Print a section header */\nexport const sectionHeader = (title: string): void => {\n console.log();\n console.log(c.brandBold(title));\n console.log(divider());\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Progress Display Modes\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type ProgressMode = 'detailed' | 'compact' | 'minimal';\n\n/** Determine the best progress display mode based on item count */\nexport const getProgressMode = (itemCount: number): ProgressMode => {\n if (itemCount <= 20) return 'detailed';\n if (itemCount <= 100) return 'compact';\n return 'minimal';\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Box Styles (for boxen)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const boxStyles = {\n /** Compact header box */\n header: {\n padding: { top: 0, bottom: 0, left: 1, right: 1 },\n borderStyle: 'round' as const,\n borderColor: 'cyan' as const,\n },\n\n /** Standard info box */\n info: {\n padding: 1,\n margin: { top: 1, bottom: 1, left: 0, right: 0 },\n borderStyle: 'round' as const,\n borderColor: 'cyan' as const,\n },\n\n /** Success box */\n success: {\n padding: 1,\n margin: { top: 1, bottom: 1, left: 0, right: 0 },\n borderStyle: 'round' as const,\n borderColor: 'green' as const,\n },\n\n /** Error box */\n error: {\n padding: 1,\n margin: { top: 1, bottom: 1, left: 0, right: 0 },\n borderStyle: 'round' as const,\n borderColor: 'red' as const,\n },\n};\n","/**\n * Banner and box utilities for tuck CLI\n * Provides ASCII art banner and styled boxes\n */\n\nimport boxen from 'boxen';\nimport { colors as c, boxStyles, indent } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ASCII Art Banner (only for init and help)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const banner = (): void => {\n const art = `\n ████████╗██╗ ██╗ ██████╗██╗ ██╗\n ╚══██╔══╝██║ ██║██╔════╝██║ ██╔╝\n ██║ ██║ ██║██║ █████╔╝ \n ██║ ██║ ██║██║ ██╔═██╗ \n ██║ ╚██████╔╝╚██████╗██║ ██╗\n ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝`;\n\n console.log(c.brand(art));\n console.log(c.muted(' Modern Dotfiles Manager\\n'));\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Mini Banner (compact version for other contexts)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const miniBanner = (): void => {\n console.log(boxen(c.brandBold('tuck') + c.muted(' · Modern Dotfiles Manager'), boxStyles.header));\n console.log();\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Help Text\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const customHelp = (version: string): string => {\n const title = boxen(c.brandBold('tuck') + c.muted(` v${version}`), boxStyles.header);\n\n const quickStart = `\n${c.brandBold('Quick Start:')}\n${indent()}${c.brand('tuck init')} Set up tuck\n${indent()}${c.brand('tuck add <file>')} Track a dotfile\n${indent()}${c.brand('tuck sync')} Commit changes\n${indent()}${c.brand('tuck push')} Push to remote\n\n${c.brandBold('New Machine:')}\n${indent()}${c.brand('tuck apply <user>')} Apply dotfiles from GitHub\n`;\n\n const commands = `\n${c.brandBold('Commands:')}\n${indent()}${c.brand('Getting Started')}\n${indent()}${indent()}init Initialize tuck\n${indent()}${indent()}scan Detect dotfiles\n${indent()}${indent()}apply <source> Apply from repo\n\n${indent()}${c.brand('Managing Files')}\n${indent()}${indent()}add <paths...> Track files\n${indent()}${indent()}remove <paths...> Untrack files\n${indent()}${indent()}list List tracked\n${indent()}${indent()}status Show status\n\n${indent()}${c.brand('Syncing')}\n${indent()}${indent()}sync Commit changes\n${indent()}${indent()}push Push to remote\n${indent()}${indent()}pull Pull from remote\n${indent()}${indent()}diff Show changes\n\n${indent()}${c.brand('Restoring')}\n${indent()}${indent()}restore Restore files\n${indent()}${indent()}undo Undo last apply\n\n${indent()}${c.brand('Config')}\n${indent()}${indent()}config Manage settings\n`;\n\n const footer = `\n${c.muted('Run')} ${c.brand('tuck <command> --help')} ${c.muted('for details')}\n${c.muted('Docs:')} ${c.brand('https://github.com/Pranav-Karra-3301/tuck')}\n`;\n\n return `${title}\\n${quickStart}${commands}${footer}`;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Styled Boxes\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const welcomeBox = (message: string, title?: string): void => {\n console.log(\n boxen(message, {\n ...boxStyles.info,\n title,\n titleAlignment: 'center',\n })\n );\n};\n\nexport const successBox = (message: string, title?: string): void => {\n console.log(\n boxen(message, {\n ...boxStyles.success,\n title: title || 'Success',\n titleAlignment: 'center',\n })\n );\n};\n\nexport const errorBox = (message: string, title?: string): void => {\n console.log(\n boxen(message, {\n ...boxStyles.error,\n title: title || 'Error',\n titleAlignment: 'center',\n })\n );\n};\n\nexport const infoBox = (message: string, title?: string): void => {\n console.log(\n boxen(message, {\n ...boxStyles.info,\n title,\n titleAlignment: 'center',\n })\n );\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Next Steps Box\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const nextSteps = (steps: string[]): void => {\n const content = steps.map((step, i) => `${c.brand(`${i + 1}.`)} ${step}`).join('\\n');\n\n console.log(\n boxen(content, {\n padding: 1,\n margin: { top: 1, bottom: 0, left: 0, right: 0 },\n borderStyle: 'round',\n borderColor: 'cyan',\n title: 'Next Steps',\n titleAlignment: 'left',\n })\n );\n};\n","/**\n * Logger utilities for tuck CLI\n * Provides consistent, styled logging output\n */\n\nimport logSymbols from 'log-symbols';\nimport figures from 'figures';\nimport { colors as c, indent as ind, divider, DIVIDER_WIDTH } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Logger {\n info: (msg: string) => void;\n success: (msg: string) => void;\n warning: (msg: string) => void;\n error: (msg: string) => void;\n debug: (msg: string) => void;\n step: (current: number, total: number, msg: string) => void;\n file: (action: 'add' | 'modify' | 'delete' | 'sync' | 'merge', path: string) => void;\n tree: (items: TreeItem[]) => void;\n blank: () => void;\n dim: (msg: string) => void;\n heading: (msg: string) => void;\n divider: () => void;\n}\n\nexport interface TreeItem {\n name: string;\n isLast: boolean;\n indent?: number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// File Action Icons\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst fileIcons = {\n add: c.success(figures.tick),\n modify: c.warning('~'),\n delete: c.error(figures.cross),\n sync: c.brand(figures.arrowRight),\n merge: c.info('+'),\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Logger Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const logger: Logger = {\n info: (msg: string) => {\n console.log(logSymbols.info, msg);\n },\n\n success: (msg: string) => {\n console.log(logSymbols.success, msg);\n },\n\n warning: (msg: string) => {\n console.log(logSymbols.warning, msg);\n },\n\n error: (msg: string) => {\n console.log(logSymbols.error, msg);\n },\n\n debug: (msg: string) => {\n if (process.env.DEBUG) {\n console.log(c.muted(figures.bullet), c.muted(msg));\n }\n },\n\n step: (current: number, total: number, msg: string) => {\n const counter = c.muted(`[${current}/${total}]`);\n console.log(counter, msg);\n },\n\n file: (action: 'add' | 'modify' | 'delete' | 'sync' | 'merge', path: string) => {\n const icon = fileIcons[action];\n console.log(`${ind()}${icon} ${c.brand(path)}`);\n },\n\n tree: (items: TreeItem[]) => {\n items.forEach(({ name, isLast, indent = 0 }) => {\n const indentation = ind(indent);\n const prefix = isLast ? figures.lineUpRight : figures.lineDownRightArc;\n console.log(c.muted(indentation + prefix + figures.line), name);\n });\n },\n\n blank: () => {\n console.log();\n },\n\n dim: (msg: string) => {\n console.log(c.muted(msg));\n },\n\n heading: (msg: string) => {\n console.log(c.brandBold(msg));\n },\n\n divider: () => {\n console.log(divider(DIVIDER_WIDTH));\n },\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Formatting Helpers (re-exported from theme for convenience)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport { formatPath, formatCategory, formatCount, formatStatus } from './theme.js';\n","/**\n * Prompts wrapper for tuck CLI\n * Uses @clack/prompts for consistent, beautiful interactive prompts\n */\n\nimport * as p from '@clack/prompts';\nimport { colors as c } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SelectOption<T> {\n value: T;\n label: string;\n hint?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Main Prompts Object\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const prompts = {\n /**\n * Display command intro header\n */\n intro: (title: string): void => {\n p.intro(c.brandBg(` ${title} `));\n },\n\n /**\n * Display command outro/success message\n */\n outro: (message: string): void => {\n p.outro(c.success(message));\n },\n\n /**\n * Confirm dialog (yes/no)\n */\n confirm: async (message: string, initial = false): Promise<boolean> => {\n const result = await p.confirm({ message, initialValue: initial });\n if (p.isCancel(result)) {\n prompts.cancel();\n }\n return result as boolean;\n },\n\n /**\n * Single select from options\n */\n select: async <T>(message: string, options: SelectOption<T>[]): Promise<T> => {\n const result = await p.select({\n message,\n options: options.map((opt) => ({\n value: opt.value,\n label: opt.label,\n hint: opt.hint,\n })),\n });\n if (p.isCancel(result)) {\n prompts.cancel();\n }\n return result as T;\n },\n\n /**\n * Multi-select from options\n */\n multiselect: async <T>(\n message: string,\n options: SelectOption<T>[],\n config?: {\n required?: boolean;\n initialValues?: T[];\n }\n ): Promise<T[]> => {\n const mappedOptions = options.map((opt) => ({\n value: opt.value,\n label: opt.label,\n hint: opt.hint ?? '',\n }));\n\n const result = await p.multiselect({\n message,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options: mappedOptions as any,\n required: config?.required ?? false,\n initialValues: config?.initialValues,\n });\n if (p.isCancel(result)) {\n prompts.cancel();\n }\n return result as T[];\n },\n\n /**\n * Text input\n */\n text: async (\n message: string,\n options?: {\n placeholder?: string;\n defaultValue?: string;\n validate?: (value: string) => string | undefined;\n }\n ): Promise<string> => {\n const result = await p.text({\n message,\n placeholder: options?.placeholder,\n defaultValue: options?.defaultValue,\n validate: options?.validate,\n });\n if (p.isCancel(result)) {\n prompts.cancel();\n }\n return result as string;\n },\n\n /**\n * Password input (hidden)\n */\n password: async (message: string): Promise<string> => {\n const result = await p.password({ message });\n if (p.isCancel(result)) {\n prompts.cancel();\n }\n return result as string;\n },\n\n /**\n * Create a spinner for async operations\n */\n spinner: () => p.spinner(),\n\n /**\n * Display a note/info box\n */\n note: (message: string, title?: string): void => {\n p.note(message, title);\n },\n\n /**\n * Cancel operation and exit\n */\n cancel: (message = 'Operation cancelled'): never => {\n p.cancel(message);\n process.exit(0);\n },\n\n /**\n * Logging helpers\n */\n log: {\n info: (message: string): void => {\n p.log.info(message);\n },\n success: (message: string): void => {\n p.log.success(message);\n },\n warning: (message: string): void => {\n p.log.warning(message);\n },\n error: (message: string): void => {\n p.log.error(message);\n },\n step: (message: string): void => {\n p.log.step(message);\n },\n message: (message: string): void => {\n p.log.message(message);\n },\n },\n\n /**\n * Group multiple prompts\n */\n group: async <T>(\n steps: Record<string, () => Promise<T | symbol>>,\n options?: { onCancel?: () => void }\n ): Promise<Record<string, T>> => {\n const results = await p.group(steps, {\n onCancel: () => {\n if (options?.onCancel) {\n options.onCancel();\n } else {\n prompts.cancel();\n }\n },\n });\n return results as Record<string, T>;\n },\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Utility Exports\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const isCancel = p.isCancel;\n","/**\n * Spinner utilities for tuck CLI\n * Uses @clack/prompts spinner as the primary implementation\n * Provides backward-compatible API with enhanced methods\n */\n\nimport * as p from '@clack/prompts';\nimport logSymbols from 'log-symbols';\nimport { colors as c } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SpinnerInstance {\n start: (text?: string) => void;\n stop: () => void;\n succeed: (text?: string) => void;\n fail: (text?: string) => void;\n warn: (text?: string) => void;\n info: (text?: string) => void;\n text: (text: string) => void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Create Spinner\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Create a spinner instance using @clack/prompts\n * Provides ora-compatible API for backward compatibility\n */\nexport const createSpinner = (initialText?: string): SpinnerInstance => {\n const spinner = p.spinner();\n let currentText = initialText || '';\n let started = false;\n\n return {\n start: (text?: string) => {\n currentText = text || currentText || 'Loading...';\n spinner.start(currentText);\n started = true;\n },\n\n stop: () => {\n if (started) {\n spinner.stop(currentText);\n started = false;\n }\n },\n\n succeed: (text?: string) => {\n if (started) {\n spinner.stop(c.success(text || currentText));\n started = false;\n } else {\n console.log(logSymbols.success, c.success(text || currentText));\n }\n },\n\n fail: (text?: string) => {\n if (started) {\n spinner.stop(c.error(text || currentText));\n started = false;\n } else {\n console.log(logSymbols.error, c.error(text || currentText));\n }\n },\n\n warn: (text?: string) => {\n if (started) {\n spinner.stop(c.warning(text || currentText));\n started = false;\n } else {\n console.log(logSymbols.warning, c.warning(text || currentText));\n }\n },\n\n info: (text?: string) => {\n if (started) {\n spinner.stop(c.info(text || currentText));\n started = false;\n } else {\n console.log(logSymbols.info, c.info(text || currentText));\n }\n },\n\n text: (text: string) => {\n currentText = text;\n if (started) {\n spinner.message(text);\n }\n },\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// With Spinner Helper\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Execute an async function with a spinner\n * Automatically shows success/failure based on result\n */\nexport const withSpinner = async <T>(\n text: string,\n fn: () => Promise<T>,\n options?: {\n successText?: string;\n failText?: string;\n }\n): Promise<T> => {\n const spinner = createSpinner(text);\n spinner.start();\n\n try {\n const result = await fn();\n spinner.succeed(options?.successText || text);\n return result;\n } catch (error) {\n spinner.fail(options?.failText || text);\n throw error;\n }\n};\n","/**\n * Table utilities for tuck CLI\n * Provides formatted table output\n */\n\nimport { colors as c } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TableColumn {\n header: string;\n key: string;\n width?: number;\n align?: 'left' | 'right' | 'center';\n format?: (value: unknown) => string;\n}\n\nexport interface TableOptions {\n columns: TableColumn[];\n border?: boolean;\n padding?: number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Utilities\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst padString = (\n str: string,\n width: number,\n align: 'left' | 'right' | 'center' = 'left'\n): string => {\n // Strip ANSI codes for length calculation\n // eslint-disable-next-line no-control-regex\n const visibleLength = str.replace(/\\x1b\\[[0-9;]*m/g, '').length;\n const padding = Math.max(0, width - visibleLength);\n\n switch (align) {\n case 'right':\n return ' '.repeat(padding) + str;\n case 'center': {\n const leftPad = Math.floor(padding / 2);\n const rightPad = padding - leftPad;\n return ' '.repeat(leftPad) + str + ' '.repeat(rightPad);\n }\n default:\n return str + ' '.repeat(padding);\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Table Creation\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const createTable = (data: Record<string, unknown>[], options: TableOptions): string => {\n const { columns, border = false, padding = 2 } = options;\n\n // Calculate column widths\n const widths = columns.map((col) => {\n const headerWidth = col.header.length;\n const maxDataWidth = data.reduce((max, row) => {\n const value = col.format ? col.format(row[col.key]) : String(row[col.key] ?? '');\n // eslint-disable-next-line no-control-regex\n const visibleLength = value.replace(/\\x1b\\[[0-9;]*m/g, '').length;\n return Math.max(max, visibleLength);\n }, 0);\n return col.width || Math.max(headerWidth, maxDataWidth);\n });\n\n const lines: string[] = [];\n const pad = ' '.repeat(padding);\n\n // Header row\n const headerRow = columns\n .map((col, i) => c.bold(padString(col.header, widths[i], col.align)))\n .join(pad);\n\n // Border line\n const borderLine = c.muted(widths.map((w) => '─'.repeat(w)).join(pad));\n\n if (border) {\n lines.push(borderLine);\n lines.push(headerRow);\n lines.push(borderLine);\n } else {\n lines.push(headerRow);\n lines.push(borderLine);\n }\n\n // Data rows\n data.forEach((row) => {\n const dataRow = columns\n .map((col, i) => {\n const value = col.format ? col.format(row[col.key]) : String(row[col.key] ?? '');\n return padString(value, widths[i], col.align);\n })\n .join(pad);\n lines.push(dataRow);\n });\n\n if (border) {\n lines.push(borderLine);\n }\n\n return lines.join('\\n');\n};\n\nexport const printTable = (data: Record<string, unknown>[], options: TableOptions): void => {\n console.log(createTable(data, options));\n};\n","/**\n * Progress display utilities for tuck CLI\n * Provides beautiful, adaptive progress displays for file operations\n *\n * Display Modes:\n * - detailed (≤20 files): Show each file with spinner\n * - compact (21-100 files): Progress bar with current file\n * - minimal (>100 files): Spinner with count only\n */\n\nimport * as p from '@clack/prompts';\nimport logSymbols from 'log-symbols';\nimport figures from 'figures';\nimport { colors as c, divider, indent, DIVIDER_WIDTH, getProgressMode } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ProgressItem {\n label: string;\n description?: string;\n}\n\nexport interface ProgressTrackerOptions {\n title?: string;\n showIndex?: boolean;\n animationDelay?: number;\n}\n\nexport interface ProgressTracker {\n start: () => void;\n update: (\n index: number,\n status: 'pending' | 'in_progress' | 'completed' | 'error',\n message?: string\n ) => void;\n complete: (message?: string) => void;\n fail: (message?: string) => void;\n}\n\nexport interface FileOperationItem {\n path: string;\n category?: string;\n action: 'tracking' | 'copying' | 'syncing' | 'restoring';\n icon?: string;\n}\n\nexport interface FileOperationOptions {\n delayBetween?: number;\n showCategory?: boolean;\n onProgress?: (current: number, total: number) => void;\n actionVerb?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Progress Bar Component\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst createProgressBarLine = (current: number, total: number, width = 30): string => {\n const percentage = Math.round((current / total) * 100);\n const filled = Math.round((current / total) * width);\n const empty = width - filled;\n\n const bar = c.brand('█').repeat(filled) + c.muted('░').repeat(empty);\n const stats = c.muted(`${current}/${total}`);\n const pct = c.bold(`${percentage}%`);\n\n return `${bar} ${pct} ${stats}`;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Detailed Mode: Show Each File\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst processDetailed = async <T>(\n items: FileOperationItem[],\n processor: (item: FileOperationItem, index: number) => Promise<T>,\n options: FileOperationOptions\n): Promise<T[]> => {\n const { showCategory = true, onProgress, actionVerb, delayBetween = 50 } = options;\n const results: T[] = [];\n const total = items.length;\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const indexStr = c.muted(`[${i + 1}/${total}]`);\n const actionText = actionVerb || getActionText(item.action);\n\n // Show spinner while processing\n const spinner = p.spinner();\n spinner.start(`${indexStr} ${actionText} ${c.brand(item.path)}`);\n\n try {\n const result = await processor(item, i);\n results.push(result);\n\n // Format completion line\n const categoryStr =\n showCategory && item.category ? c.muted(` [${item.icon || ''}${item.category}]`) : '';\n\n spinner.stop(`${logSymbols.success} ${indexStr} ${item.path}${categoryStr}`);\n\n if (onProgress) {\n onProgress(i + 1, total);\n }\n\n // Small delay for visual effect (except last item)\n if (i < items.length - 1 && delayBetween > 0) {\n await sleep(delayBetween);\n }\n } catch (error) {\n spinner.stop(`${logSymbols.error} ${indexStr} ${item.path} ${c.error('failed')}`);\n throw error;\n }\n }\n\n return results;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Compact Mode: Progress Bar + Current File\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst processCompact = async <T>(\n items: FileOperationItem[],\n processor: (item: FileOperationItem, index: number) => Promise<T>,\n options: FileOperationOptions\n): Promise<T[]> => {\n const { onProgress, delayBetween = 10 } = options;\n const results: T[] = [];\n const total = items.length;\n\n // Track if we've written output that needs clearing\n let hasOutput = false;\n\n const clearLines = () => {\n if (hasOutput) {\n // Move cursor up one line, clear it, move up again, clear it\n process.stdout.write('\\x1b[1A\\x1b[2K\\x1b[1A\\x1b[2K');\n }\n };\n\n const writeProgress = (progressBar: string, currentFile: string) => {\n if (hasOutput) {\n clearLines();\n }\n console.log(`${indent()}${progressBar}`);\n console.log(`${indent()}${c.brand(figures.pointer)} ${currentFile}`);\n hasOutput = true;\n };\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n\n // Show progress bar + current file\n const progressBar = createProgressBarLine(i, total);\n const currentFile = c.muted(truncatePath(item.path, 40));\n writeProgress(progressBar, currentFile);\n\n try {\n const result = await processor(item, i);\n results.push(result);\n\n if (onProgress) {\n onProgress(i + 1, total);\n }\n\n if (delayBetween > 0) {\n await sleep(delayBetween);\n }\n } catch (error) {\n clearLines();\n console.log(`${indent()}${logSymbols.error} ${item.path} ${c.error('failed')}`);\n throw error;\n }\n }\n\n // Final state - clear and show completed progress bar\n clearLines();\n const finalBar = createProgressBarLine(total, total);\n console.log(`${indent()}${finalBar}`);\n\n return results;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Minimal Mode: Spinner with Count\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst processMinimal = async <T>(\n items: FileOperationItem[],\n processor: (item: FileOperationItem, index: number) => Promise<T>,\n options: FileOperationOptions\n): Promise<T[]> => {\n const { actionVerb, onProgress, delayBetween = 5 } = options;\n const results: T[] = [];\n const total = items.length;\n const actionText = actionVerb || 'Processing';\n\n const spinner = p.spinner();\n spinner.start(`${actionText} ${total} files...`);\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const pct = Math.round(((i + 1) / total) * 100);\n\n spinner.message(`${actionText}... ${i + 1}/${total} (${pct}%)`);\n\n try {\n const result = await processor(item, i);\n results.push(result);\n\n if (onProgress) {\n onProgress(i + 1, total);\n }\n\n if (delayBetween > 0 && i < items.length - 1) {\n await sleep(delayBetween);\n }\n } catch (error) {\n spinner.stop(`${logSymbols.error} Failed at ${item.path}`);\n throw error;\n }\n }\n\n spinner.stop(`${logSymbols.success} ${actionText} complete`);\n return results;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Main Entry Point\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Process files with adaptive progress display\n * Automatically selects the best display mode based on item count\n */\nexport const processFilesWithProgress = async <T>(\n items: FileOperationItem[],\n processor: (item: FileOperationItem, index: number) => Promise<T>,\n options: FileOperationOptions = {}\n): Promise<T[]> => {\n const { actionVerb } = options;\n const total = items.length;\n const mode = getProgressMode(total);\n\n // Header\n const displayAction = actionVerb || getActionText(items[0]?.action || 'tracking');\n console.log();\n console.log(c.brandBold(`${displayAction} ${total} ${total === 1 ? 'file' : 'files'}...`));\n console.log(divider(DIVIDER_WIDTH));\n console.log();\n\n // Process based on mode\n let results: T[];\n\n switch (mode) {\n case 'detailed':\n results = await processDetailed(items, processor, options);\n break;\n case 'compact':\n results = await processCompact(items, processor, options);\n break;\n case 'minimal':\n results = await processMinimal(items, processor, options);\n break;\n }\n\n // Summary\n console.log();\n const pastTense = getPastTense(displayAction);\n console.log(\n logSymbols.success,\n c.bold(`${pastTense} ${total} ${total === 1 ? 'file' : 'files'}`)\n );\n\n return results;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Legacy Exports (backward compatibility)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** @deprecated Use processFilesWithProgress instead */\nexport const trackFilesWithProgress = processFilesWithProgress;\n\n/** @deprecated Use FileOperationItem instead */\nexport type FileTrackingItem = FileOperationItem;\n\n/** @deprecated Use FileOperationOptions instead */\nexport type FileTrackingOptions = FileOperationOptions;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Step Progress (for multi-step operations)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface StepProgress {\n start: (text: string) => void;\n succeed: (text?: string) => void;\n fail: (text?: string) => void;\n skip: (text?: string) => void;\n}\n\nexport const createStepProgress = (totalSteps: number): StepProgress => {\n let currentStep = 0;\n let spinner: ReturnType<typeof p.spinner> | null = null;\n let currentText = '';\n\n return {\n start: (text: string) => {\n currentStep++;\n currentText = text;\n const stepStr = c.muted(`[${currentStep}/${totalSteps}]`);\n spinner = p.spinner();\n spinner.start(`${stepStr} ${text}`);\n },\n\n succeed: (text?: string) => {\n if (spinner) {\n const stepStr = c.muted(`[${currentStep}/${totalSteps}]`);\n spinner.stop(`${logSymbols.success} ${stepStr} ${text || currentText}`);\n spinner = null;\n }\n },\n\n fail: (text?: string) => {\n if (spinner) {\n const stepStr = c.muted(`[${currentStep}/${totalSteps}]`);\n spinner.stop(`${logSymbols.error} ${stepStr} ${text || currentText}`);\n spinner = null;\n }\n },\n\n skip: (text?: string) => {\n if (spinner) {\n const stepStr = c.muted(`[${currentStep}/${totalSteps}]`);\n spinner.stop(\n `${logSymbols.info} ${stepStr} ${text || currentText} ${c.muted('(skipped)')}`\n );\n spinner = null;\n }\n },\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Simple Progress Bar\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const createProgressBar = (\n total: number,\n options: { width?: number; label?: string } = {}\n): { update: (current: number, label?: string) => void; complete: () => void } => {\n const { width = 30, label = 'Progress' } = options;\n let lastOutput = '';\n\n const render = (current: number, currentLabel?: string) => {\n const bar = createProgressBarLine(current, total, width);\n const labelStr = currentLabel || label;\n const output = `${indent()}${bar} ${labelStr}`;\n\n // Clear previous line and write new one\n if (lastOutput) {\n process.stdout.write('\\r' + ' '.repeat(lastOutput.length) + '\\r');\n }\n process.stdout.write(output);\n lastOutput = output;\n };\n\n return {\n update: (current: number, currentLabel?: string) => {\n render(current, currentLabel);\n },\n complete: () => {\n if (lastOutput) {\n process.stdout.write('\\r' + ' '.repeat(lastOutput.length) + '\\r');\n }\n console.log(`${indent()}${logSymbols.success} ${label} complete`);\n },\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Operation Summary\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const showOperationSummary = (\n stats: {\n tracked?: number;\n copied?: number;\n synced?: number;\n failed?: number;\n skipped?: number;\n },\n title = 'Summary'\n): void => {\n console.log();\n console.log(c.brandBold(`${title}:`));\n\n if (stats.tracked !== undefined && stats.tracked > 0) {\n console.log(\n `${indent()}${logSymbols.success} Tracked: ${stats.tracked} ${stats.tracked === 1 ? 'file' : 'files'}`\n );\n }\n if (stats.copied !== undefined && stats.copied > 0) {\n console.log(\n `${indent()}${logSymbols.success} Copied: ${stats.copied} ${stats.copied === 1 ? 'file' : 'files'}`\n );\n }\n if (stats.synced !== undefined && stats.synced > 0) {\n console.log(\n `${indent()}${logSymbols.success} Synced: ${stats.synced} ${stats.synced === 1 ? 'file' : 'files'}`\n );\n }\n if (stats.skipped !== undefined && stats.skipped > 0) {\n console.log(\n `${indent()}${c.muted(figures.circle)} Skipped: ${stats.skipped} ${stats.skipped === 1 ? 'file' : 'files'}`\n );\n }\n if (stats.failed !== undefined && stats.failed > 0) {\n console.log(\n `${indent()}${logSymbols.error} Failed: ${stats.failed} ${stats.failed === 1 ? 'file' : 'files'}`\n );\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Utilities\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst getActionText = (action: string): string => {\n const texts: Record<string, string> = {\n tracking: 'Tracking',\n copying: 'Copying',\n syncing: 'Syncing',\n restoring: 'Restoring',\n };\n return texts[action] || 'Processing';\n};\n\nconst getPastTense = (verb: string): string => {\n if (verb.endsWith('ing')) {\n const base = verb.slice(0, -3);\n // Handle consonant + y -> ied (e.g., Copy -> Copied)\n if (base.endsWith('y') && base.length > 1) {\n const beforeY = base[base.length - 2];\n // Check if preceded by consonant (not a vowel)\n if (!'aeiouAEIOU'.includes(beforeY)) {\n return base.slice(0, -1) + 'ied';\n }\n }\n // Handle words ending in 'e' that was dropped (e.g., Sync -> Synced)\n // Most -ing words just need +ed on the base\n return base + 'ed';\n }\n return verb;\n};\n\nconst truncatePath = (path: string, maxLength: number): string => {\n if (path.length <= maxLength) return path;\n return '...' + path.slice(-(maxLength - 3));\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Legacy Progress Tracker (for backward compatibility)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const createProgressTracker = (\n items: ProgressItem[],\n options: ProgressTrackerOptions = {}\n): ProgressTracker => {\n const { title, showIndex = true } = options;\n const total = items.length;\n const statuses: ('pending' | 'in_progress' | 'completed' | 'error')[] = items.map(\n () => 'pending'\n );\n let spinner: ReturnType<typeof p.spinner> | null = null;\n let currentIndex = -1;\n\n const getIcon = (status: 'pending' | 'in_progress' | 'completed' | 'error'): string => {\n switch (status) {\n case 'pending':\n return c.muted(figures.circle);\n case 'in_progress':\n return c.brand(figures.circleFilled);\n case 'completed':\n return logSymbols.success;\n case 'error':\n return logSymbols.error;\n }\n };\n\n const renderLine = (index: number): string => {\n const item = items[index];\n const status = statuses[index];\n const icon = getIcon(status);\n const indexStr = showIndex ? c.muted(`[${index + 1}/${total}]`) + ' ' : '';\n\n let line = `${indent()}${icon} ${indexStr}${item.label}`;\n\n if (item.description && status !== 'in_progress') {\n line += c.muted(` - ${item.description}`);\n }\n\n return line;\n };\n\n return {\n start: () => {\n if (title) {\n console.log();\n console.log(c.brandBold(title));\n console.log(divider(DIVIDER_WIDTH));\n }\n },\n\n update: (\n index: number,\n status: 'pending' | 'in_progress' | 'completed' | 'error',\n message?: string\n ) => {\n statuses[index] = status;\n\n if (status === 'in_progress') {\n if (spinner) {\n spinner.stop();\n }\n\n currentIndex = index;\n const item = items[index];\n const indexStr = showIndex ? c.muted(`[${index + 1}/${total}]`) + ' ' : '';\n\n spinner = p.spinner();\n spinner.start(`${indexStr}${message || item.label}`);\n } else if (status === 'completed' || status === 'error') {\n if (spinner && currentIndex === index) {\n spinner.stop(renderLine(index));\n spinner = null;\n } else {\n console.log(renderLine(index));\n }\n }\n },\n\n complete: (message?: string) => {\n if (spinner) {\n spinner.stop();\n spinner = null;\n }\n console.log();\n console.log(logSymbols.success, message || 'Completed successfully');\n },\n\n fail: (message?: string) => {\n if (spinner) {\n spinner.stop();\n spinner = null;\n }\n console.log();\n console.log(logSymbols.error, message || 'Operation failed');\n },\n };\n};\n","/**\n * UI module exports for tuck CLI\n */\n\n// Theme system (design tokens, colors, icons)\nexport * from './theme.js';\n\n// Components\nexport * from './banner.js';\nexport * from './logger.js';\nexport * from './prompts.js';\nexport * from './spinner.js';\nexport * from './table.js';\nexport * from './progress.js';\n","import { homedir } from 'os';\nimport { join, dirname } from 'path';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport figures from 'figures';\n\n// Read version from package.json at runtime\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst packageJsonPath = join(__dirname, '..', 'package.json');\nlet VERSION_VALUE = '1.0.0'; // fallback\ntry {\n const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n VERSION_VALUE = pkg.version;\n} catch {\n // Fallback if package.json can't be read (e.g., bundled)\n}\nexport const VERSION = VERSION_VALUE;\nexport const DESCRIPTION = 'Modern dotfiles manager with a beautiful CLI';\nexport const APP_NAME = 'tuck';\n\nexport const HOME_DIR = homedir();\nexport const DEFAULT_TUCK_DIR = join(HOME_DIR, '.tuck');\nexport const MANIFEST_FILE = '.tuckmanifest.json';\nexport const CONFIG_FILE = '.tuckrc.json';\nexport const BACKUP_DIR = join(HOME_DIR, '.tuck-backups');\nexport const FILES_DIR = 'files';\n\nexport const MANIFEST_VERSION = '1.0.0';\n\nexport interface CategoryConfig {\n patterns: string[];\n icon: string;\n}\n\nexport const CATEGORIES: Record<string, CategoryConfig> = {\n shell: {\n patterns: [\n '.zshrc',\n '.bashrc',\n '.bash_profile',\n '.zprofile',\n '.profile',\n '.aliases',\n '.zshenv',\n '.bash_aliases',\n '.inputrc',\n ],\n icon: '$',\n },\n git: {\n patterns: ['.gitconfig', '.gitignore_global', '.gitmessage', '.gitattributes'],\n icon: figures.star,\n },\n editors: {\n patterns: [\n '.vimrc',\n '.config/nvim',\n '.emacs',\n '.emacs.d',\n '.config/Code',\n '.ideavimrc',\n '.nanorc',\n ],\n icon: figures.pointer,\n },\n terminal: {\n patterns: [\n '.tmux.conf',\n '.config/alacritty',\n '.config/kitty',\n '.wezterm.lua',\n '.config/wezterm',\n '.config/hyper',\n '.config/starship.toml',\n ],\n icon: '#',\n },\n ssh: {\n patterns: ['.ssh/config'],\n icon: figures.warning,\n },\n misc: {\n patterns: [],\n icon: figures.bullet,\n },\n};\n\nexport const COMMON_DOTFILES = [\n { path: '~/.zshrc', category: 'shell' },\n { path: '~/.bashrc', category: 'shell' },\n { path: '~/.bash_profile', category: 'shell' },\n { path: '~/.gitconfig', category: 'git' },\n { path: '~/.config/nvim', category: 'editors' },\n { path: '~/.vimrc', category: 'editors' },\n { path: '~/.tmux.conf', category: 'terminal' },\n { path: '~/.ssh/config', category: 'ssh' },\n { path: '~/.config/starship.toml', category: 'terminal' },\n];\n","import { homedir } from 'os';\nimport { join, basename, dirname, relative, isAbsolute, resolve, sep } from 'path';\nimport { stat, access } from 'fs/promises';\nimport { constants } from 'fs';\nimport { DEFAULT_TUCK_DIR, FILES_DIR, MANIFEST_FILE, CONFIG_FILE, CATEGORIES } from '../constants.js';\n\nexport const expandPath = (path: string): string => {\n if (path.startsWith('~/')) {\n return join(homedir(), path.slice(2));\n }\n if (path.startsWith('$HOME/')) {\n return join(homedir(), path.slice(6));\n }\n return isAbsolute(path) ? path : resolve(path);\n};\n\nexport const collapsePath = (path: string): string => {\n const home = homedir();\n if (path.startsWith(home)) {\n return '~' + path.slice(home.length);\n }\n return path;\n};\n\nexport const getTuckDir = (customDir?: string): string => {\n return expandPath(customDir || DEFAULT_TUCK_DIR);\n};\n\nexport const getManifestPath = (tuckDir: string): string => {\n return join(tuckDir, MANIFEST_FILE);\n};\n\nexport const getConfigPath = (tuckDir: string): string => {\n return join(tuckDir, CONFIG_FILE);\n};\n\nexport const getFilesDir = (tuckDir: string): string => {\n return join(tuckDir, FILES_DIR);\n};\n\nexport const getCategoryDir = (tuckDir: string, category: string): string => {\n return join(getFilesDir(tuckDir), category);\n};\n\nexport const getDestinationPath = (tuckDir: string, category: string, filename: string): string => {\n return join(getCategoryDir(tuckDir, category), filename);\n};\n\nexport const getRelativeDestination = (category: string, filename: string): string => {\n return join(FILES_DIR, category, filename);\n};\n\nexport const sanitizeFilename = (filepath: string): string => {\n const base = basename(filepath);\n // Remove leading dot for storage, but keep track that it was a dotfile\n return base.startsWith('.') ? base.slice(1) : base;\n};\n\nexport const detectCategory = (filepath: string): string => {\n const expandedPath = expandPath(filepath);\n const relativePath = collapsePath(expandedPath);\n\n for (const [category, config] of Object.entries(CATEGORIES)) {\n for (const pattern of config.patterns) {\n // Check if the pattern matches the path\n if (relativePath.endsWith(pattern) || relativePath.includes(pattern)) {\n return category;\n }\n // Check just the filename\n const filename = basename(expandedPath);\n if (filename === pattern || filename === basename(pattern)) {\n return category;\n }\n }\n }\n\n return 'misc';\n};\n\nexport const pathExists = async (path: string): Promise<boolean> => {\n try {\n await access(path, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n};\n\nexport const isDirectory = async (path: string): Promise<boolean> => {\n try {\n const stats = await stat(path);\n return stats.isDirectory();\n } catch {\n return false;\n }\n};\n\nexport const isFile = async (path: string): Promise<boolean> => {\n try {\n const stats = await stat(path);\n return stats.isFile();\n } catch {\n return false;\n }\n};\n\nexport const isSymlink = async (path: string): Promise<boolean> => {\n try {\n const stats = await stat(path);\n return stats.isSymbolicLink();\n } catch {\n return false;\n }\n};\n\nexport const isReadable = async (path: string): Promise<boolean> => {\n try {\n await access(path, constants.R_OK);\n return true;\n } catch {\n return false;\n }\n};\n\nexport const isWritable = async (path: string): Promise<boolean> => {\n try {\n await access(path, constants.W_OK);\n return true;\n } catch {\n return false;\n }\n};\n\nexport const getRelativePath = (from: string, to: string): string => {\n return relative(dirname(from), to);\n};\n\n/**\n * Validate that a path is safely within the user's home directory.\n * Prevents path traversal attacks from malicious manifests.\n * @returns true if the path is within home directory, false otherwise\n */\nexport const isPathWithinHome = (path: string): boolean => {\n const home = homedir();\n const expandedPath = expandPath(path);\n const normalizedPath = resolve(expandedPath);\n const normalizedHome = resolve(home);\n\n // Check if the normalized path starts with the home directory\n // Use path.sep for cross-platform compatibility (/ on POSIX, \\ on Windows)\n return normalizedPath.startsWith(normalizedHome + sep) || normalizedPath === normalizedHome;\n};\n\n/**\n * Validate that a source path from a manifest is safe to use.\n * Throws an error if the path is unsafe (path traversal attempt).\n */\nexport const validateSafeSourcePath = (source: string): void => {\n // Reject absolute paths that don't start with home-relative prefixes\n if (isAbsolute(source) && !source.startsWith(homedir())) {\n throw new Error(`Unsafe path detected: ${source} - absolute paths outside home directory are not allowed`);\n }\n\n // Reject obvious path traversal attempts\n if (source.includes('../') || source.includes('..\\\\')) {\n throw new Error(`Unsafe path detected: ${source} - path traversal is not allowed`);\n }\n\n // Validate the expanded path is within home\n if (!isPathWithinHome(source)) {\n throw new Error(`Unsafe path detected: ${source} - paths must be within home directory`);\n }\n};\n\nexport const generateFileId = (source: string): string => {\n // Create a unique ID from the source path\n const collapsed = collapsePath(source);\n // Remove special characters and create a readable ID\n return collapsed\n .replace(/^~\\//, '')\n .replace(/\\//g, '_')\n .replace(/\\./g, '-')\n .replace(/^-/, '');\n};\n","/**\n * Zod schemas for secret scanning configuration\n */\n\nimport { z } from 'zod';\n\n/**\n * Schema for custom secret patterns defined by users\n */\nexport const customPatternSchema = z.object({\n name: z.string().optional(),\n pattern: z.string(),\n severity: z.enum(['critical', 'high', 'medium', 'low']).optional().default('high'),\n description: z.string().optional(),\n placeholder: z.string().optional(),\n flags: z.string().optional().default('g'),\n});\n\n/**\n * Schema for security configuration\n */\nexport const securityConfigSchema = z\n .object({\n // Enable/disable secret scanning\n scanSecrets: z.boolean().default(true),\n\n // Block operations when secrets are detected (vs just warn)\n blockOnSecrets: z.boolean().default(true),\n\n // Minimum severity level to report\n minSeverity: z.enum(['critical', 'high', 'medium', 'low']).default('high'),\n\n // Scanner to use: 'builtin' or external tools\n scanner: z.enum(['builtin', 'gitleaks', 'trufflehog']).default('builtin'),\n\n // Path to gitleaks binary (if using gitleaks scanner)\n gitleaksPath: z.string().optional(),\n\n // Path to trufflehog binary (if using trufflehog scanner)\n trufflehogPath: z.string().optional(),\n\n // Custom patterns to add to the built-in patterns\n customPatterns: z.array(customPatternSchema).default([]),\n\n // Pattern IDs to exclude from scanning\n excludePatterns: z.array(z.string()).default([]),\n\n // File patterns to exclude from scanning (glob patterns)\n excludeFiles: z.array(z.string()).default([]),\n\n // Maximum file size to scan (in bytes)\n maxFileSize: z.number().default(10 * 1024 * 1024), // 10MB\n })\n .partial()\n .default({});\n\n/**\n * Schema for the secrets store file (secrets.local.json)\n */\nexport const secretEntrySchema = z.object({\n value: z.string(),\n placeholder: z.string(),\n description: z.string().optional(),\n source: z.string().optional(),\n addedAt: z.string(),\n lastUsed: z.string().optional(),\n});\n\nexport const secretsStoreSchema = z.object({\n version: z.string().default('1.0.0'),\n secrets: z.record(secretEntrySchema).default({}),\n});\n\n// Type exports\nexport type CustomPattern = z.infer<typeof customPatternSchema>;\nexport type SecurityConfig = z.infer<typeof securityConfigSchema>;\nexport type SecretEntry = z.infer<typeof secretEntrySchema>;\nexport type SecretsStore = z.infer<typeof secretsStoreSchema>;\n","import { z } from 'zod';\nimport { securityConfigSchema } from './secrets.schema.js';\n\nexport const fileStrategySchema = z.enum(['copy', 'symlink']);\n\nexport const categoryConfigSchema = z.object({\n patterns: z.array(z.string()),\n icon: z.string().optional(),\n});\n\nexport const tuckConfigSchema = z.object({\n repository: z\n .object({\n path: z.string(),\n defaultBranch: z.string().default('main'),\n autoCommit: z.boolean().default(true),\n autoPush: z.boolean().default(false),\n })\n .partial()\n .default({}),\n\n files: z\n .object({\n strategy: fileStrategySchema.default('copy'),\n backupOnRestore: z.boolean().default(true),\n backupDir: z.string().optional(),\n })\n .partial()\n .default({}),\n\n categories: z.record(categoryConfigSchema).optional().default({}),\n\n ignore: z.array(z.string()).optional().default([]),\n\n hooks: z\n .object({\n preSync: z.string().optional(),\n postSync: z.string().optional(),\n preRestore: z.string().optional(),\n postRestore: z.string().optional(),\n })\n .partial()\n .default({}),\n\n templates: z\n .object({\n enabled: z.boolean().default(false),\n variables: z.record(z.string()).default({}),\n })\n .partial()\n .default({}),\n\n encryption: z\n .object({\n enabled: z.boolean().default(false),\n gpgKey: z.string().optional(),\n files: z.array(z.string()).default([]),\n })\n .partial()\n .default({}),\n\n ui: z\n .object({\n colors: z.boolean().default(true),\n emoji: z.boolean().default(true),\n verbose: z.boolean().default(false),\n })\n .partial()\n .default({}),\n\n security: securityConfigSchema,\n});\n\nexport type TuckConfigInput = z.input<typeof tuckConfigSchema>;\nexport type TuckConfigOutput = z.output<typeof tuckConfigSchema>;\n\nexport const defaultConfig: TuckConfigOutput = {\n repository: {\n defaultBranch: 'main',\n autoCommit: true,\n autoPush: false,\n },\n files: {\n strategy: 'copy',\n backupOnRestore: true,\n },\n categories: {},\n ignore: [],\n hooks: {},\n templates: {\n enabled: false,\n variables: {},\n },\n encryption: {\n enabled: false,\n files: [],\n },\n ui: {\n colors: true,\n emoji: true,\n verbose: false,\n },\n security: {\n scanSecrets: true,\n blockOnSecrets: true,\n minSeverity: 'high',\n scanner: 'builtin',\n customPatterns: [],\n excludePatterns: [],\n excludeFiles: [],\n maxFileSize: 10 * 1024 * 1024,\n },\n};\n","import chalk from 'chalk';\n\nexport class TuckError extends Error {\n constructor(\n message: string,\n public code: string,\n public suggestions?: string[]\n ) {\n super(message);\n this.name = 'TuckError';\n }\n}\n\nexport class NotInitializedError extends TuckError {\n constructor() {\n super('Tuck is not initialized in this system', 'NOT_INITIALIZED', [\n 'Run `tuck init` to get started',\n ]);\n }\n}\n\nexport class AlreadyInitializedError extends TuckError {\n constructor(path: string) {\n super(`Tuck is already initialized at ${path}`, 'ALREADY_INITIALIZED', [\n 'Use `tuck status` to see current state',\n `Remove ${path} to reinitialize`,\n ]);\n }\n}\n\nexport class FileNotFoundError extends TuckError {\n constructor(path: string) {\n super(`File not found: ${path}`, 'FILE_NOT_FOUND', [\n 'Check that the path is correct',\n 'Use absolute paths or paths relative to home directory',\n ]);\n }\n}\n\nexport class FileNotTrackedError extends TuckError {\n constructor(path: string) {\n super(`File is not tracked: ${path}`, 'FILE_NOT_TRACKED', [\n `Run \\`tuck add ${path}\\` to track this file`,\n 'Run `tuck list` to see all tracked files',\n ]);\n }\n}\n\nexport class FileAlreadyTrackedError extends TuckError {\n constructor(path: string) {\n super(`File is already tracked: ${path}`, 'FILE_ALREADY_TRACKED', [\n 'Run `tuck sync` to update it',\n `Run \\`tuck remove ${path}\\` to untrack`,\n ]);\n }\n}\n\nexport class GitError extends TuckError {\n constructor(message: string, gitError?: string) {\n super(`Git operation failed: ${message}`, 'GIT_ERROR', gitError ? [gitError] : undefined);\n }\n}\n\nexport class ConfigError extends TuckError {\n constructor(message: string) {\n super(`Configuration error: ${message}`, 'CONFIG_ERROR', [\n 'Run `tuck config edit` to fix configuration',\n 'Run `tuck config reset` to restore defaults',\n ]);\n }\n}\n\nexport class ManifestError extends TuckError {\n constructor(message: string) {\n super(`Manifest error: ${message}`, 'MANIFEST_ERROR', [\n 'The manifest file may be corrupted',\n 'Run `tuck init --from <remote>` to restore from remote',\n ]);\n }\n}\n\nexport class PermissionError extends TuckError {\n constructor(path: string, operation: string) {\n super(`Permission denied: cannot ${operation} ${path}`, 'PERMISSION_ERROR', [\n 'Check file permissions',\n 'Try running with appropriate permissions',\n ]);\n }\n}\n\nexport class GitHubCliError extends TuckError {\n constructor(message: string, suggestions?: string[]) {\n super(\n `GitHub CLI error: ${message}`,\n 'GITHUB_CLI_ERROR',\n suggestions || ['Install GitHub CLI: https://cli.github.com/', 'Run `gh auth login` to authenticate']\n );\n }\n}\n\nexport class BackupError extends TuckError {\n constructor(message: string, suggestions?: string[]) {\n super(`Backup error: ${message}`, 'BACKUP_ERROR', suggestions || ['Check available disk space']);\n }\n}\n\nexport class SecretsDetectedError extends TuckError {\n constructor(count: number, files: string[]) {\n const fileList = files.slice(0, 3).join(', ') + (files.length > 3 ? ` and ${files.length - 3} more` : '');\n \n // Tailor suggestions based on interactive vs CI/CD context\n const isInteractive = !!process.stdout.isTTY && process.env.CI !== 'true';\n const suggestions = isInteractive\n ? [\n 'Review the detected secrets and choose how to proceed',\n 'Use --force to bypass secret scanning (not recommended)',\n 'Run `tuck secrets list` to see stored secrets',\n 'Configure scanning with `tuck config set security.scanSecrets false`',\n ]\n : [\n 'Review the detected secrets in your source and choose how to proceed before re-running in CI',\n 'Use --force to bypass secret scanning (not recommended) if you are sure the secrets are safe to ignore',\n 'If needed, run `tuck secrets list` in a local interactive environment to inspect stored secrets',\n 'Configure scanning with `tuck config set security.scanSecrets false` if this check is not desired in CI',\n ];\n \n super(`Found ${count} potential secret(s) in: ${fileList}`, 'SECRETS_DETECTED', suggestions);\n }\n}\n\nexport const handleError = (error: unknown): never => {\n if (error instanceof TuckError) {\n console.error(chalk.red('x'), error.message);\n if (error.suggestions && error.suggestions.length > 0) {\n console.error();\n console.error(chalk.dim('Suggestions:'));\n error.suggestions.forEach((s) => console.error(chalk.dim(` → ${s}`)));\n }\n process.exit(1);\n }\n\n if (error instanceof Error) {\n console.error(chalk.red('x'), 'An unexpected error occurred:', error.message);\n if (process.env.DEBUG) {\n console.error(error.stack);\n }\n process.exit(1);\n }\n\n console.error(chalk.red('x'), 'An unknown error occurred');\n process.exit(1);\n};\n","import { readFile, writeFile } from 'fs/promises';\nimport { dirname } from 'path';\nimport { cosmiconfig } from 'cosmiconfig';\nimport { tuckConfigSchema, defaultConfig, type TuckConfigOutput } from '../schemas/config.schema.js';\nimport { getConfigPath, pathExists, getTuckDir } from './paths.js';\nimport { ConfigError } from '../errors.js';\nimport { BACKUP_DIR } from '../constants.js';\n\nlet cachedConfig: TuckConfigOutput | null = null;\nlet cachedTuckDir: string | null = null;\n\nexport const loadConfig = async (tuckDir?: string): Promise<TuckConfigOutput> => {\n const dir = tuckDir || getTuckDir();\n\n // Return cached config if same directory\n if (cachedConfig && cachedTuckDir === dir) {\n return cachedConfig;\n }\n\n const configPath = getConfigPath(dir);\n\n if (!(await pathExists(configPath))) {\n // Return default config if no config file exists\n cachedConfig = { ...defaultConfig, repository: { ...defaultConfig.repository, path: dir } };\n cachedTuckDir = dir;\n return cachedConfig;\n }\n\n try {\n const content = await readFile(configPath, 'utf-8');\n const rawConfig = JSON.parse(content);\n const result = tuckConfigSchema.safeParse(rawConfig);\n\n if (!result.success) {\n throw new ConfigError(`Invalid configuration: ${result.error.message}`);\n }\n\n // Merge with defaults\n cachedConfig = {\n ...defaultConfig,\n ...result.data,\n repository: {\n ...defaultConfig.repository,\n ...result.data.repository,\n path: dir,\n },\n files: {\n ...defaultConfig.files,\n ...result.data.files,\n backupDir: result.data.files?.backupDir || BACKUP_DIR,\n },\n };\n cachedTuckDir = dir;\n\n return cachedConfig;\n } catch (error) {\n if (error instanceof ConfigError) {\n throw error;\n }\n if (error instanceof SyntaxError) {\n throw new ConfigError('Configuration file contains invalid JSON');\n }\n throw new ConfigError(`Failed to load configuration: ${error}`);\n }\n};\n\nexport const saveConfig = async (\n config: Partial<TuckConfigOutput>,\n tuckDir?: string\n): Promise<void> => {\n const dir = tuckDir || getTuckDir();\n const configPath = getConfigPath(dir);\n\n // Load existing config and merge\n const existing = await loadConfig(dir);\n const merged = {\n ...existing,\n ...config,\n repository: {\n ...existing.repository,\n ...config.repository,\n },\n files: {\n ...existing.files,\n ...config.files,\n },\n hooks: {\n ...existing.hooks,\n ...config.hooks,\n },\n templates: {\n ...existing.templates,\n ...config.templates,\n },\n encryption: {\n ...existing.encryption,\n ...config.encryption,\n },\n ui: {\n ...existing.ui,\n ...config.ui,\n },\n };\n\n // Validate before saving\n const result = tuckConfigSchema.safeParse(merged);\n if (!result.success) {\n throw new ConfigError(`Invalid configuration: ${result.error.message}`);\n }\n\n try {\n await writeFile(configPath, JSON.stringify(result.data, null, 2) + '\\n', 'utf-8');\n // Update cache\n cachedConfig = result.data;\n cachedTuckDir = dir;\n } catch (error) {\n throw new ConfigError(`Failed to save configuration: ${error}`);\n }\n};\n\nexport const getConfigValue = async <K extends keyof TuckConfigOutput>(\n key: K,\n tuckDir?: string\n): Promise<TuckConfigOutput[K]> => {\n const config = await loadConfig(tuckDir);\n return config[key];\n};\n\nexport const setConfigValue = async <K extends keyof TuckConfigOutput>(\n key: K,\n value: TuckConfigOutput[K],\n tuckDir?: string\n): Promise<void> => {\n await saveConfig({ [key]: value } as Partial<TuckConfigOutput>, tuckDir);\n};\n\nexport const resetConfig = async (tuckDir?: string): Promise<void> => {\n const dir = tuckDir || getTuckDir();\n const configPath = getConfigPath(dir);\n\n const resetTo = { ...defaultConfig, repository: { ...defaultConfig.repository, path: dir } };\n\n try {\n await writeFile(configPath, JSON.stringify(resetTo, null, 2) + '\\n', 'utf-8');\n cachedConfig = resetTo;\n cachedTuckDir = dir;\n } catch (error) {\n throw new ConfigError(`Failed to reset configuration: ${error}`);\n }\n};\n\nexport const clearConfigCache = (): void => {\n cachedConfig = null;\n cachedTuckDir = null;\n};\n\nexport const findTuckDir = async (): Promise<string | null> => {\n // First check default location\n const defaultDir = getTuckDir();\n if (await pathExists(getConfigPath(defaultDir))) {\n return defaultDir;\n }\n\n // Try cosmiconfig to find config in current directory or parents\n const explorer = cosmiconfig('tuck', {\n searchPlaces: [\n '.tuckrc',\n '.tuckrc.json',\n '.tuckrc.yaml',\n '.tuckrc.yml',\n 'tuck.config.js',\n 'tuck.config.cjs',\n ],\n });\n\n try {\n const result = await explorer.search();\n if (result?.filepath) {\n // Return the directory containing the config file, not the file path itself\n return dirname(result.filepath);\n }\n } catch {\n // Ignore search errors\n }\n\n return null;\n};\n","import { z } from 'zod';\n\nexport const fileStrategySchema = z.enum(['copy', 'symlink']);\n\nexport const trackedFileSchema = z.object({\n source: z.string(),\n destination: z.string(),\n category: z.string(),\n strategy: fileStrategySchema,\n encrypted: z.boolean().default(false),\n template: z.boolean().default(false),\n permissions: z.string().optional(),\n added: z.string(),\n modified: z.string(),\n checksum: z.string(),\n});\n\nexport const tuckManifestSchema = z.object({\n version: z.string(),\n created: z.string(),\n updated: z.string(),\n machine: z.string().optional(),\n files: z.record(trackedFileSchema),\n});\n\nexport type TrackedFileInput = z.input<typeof trackedFileSchema>;\nexport type TrackedFileOutput = z.output<typeof trackedFileSchema>;\nexport type TuckManifestInput = z.input<typeof tuckManifestSchema>;\nexport type TuckManifestOutput = z.output<typeof tuckManifestSchema>;\n\nexport const createEmptyManifest = (machine?: string): TuckManifestOutput => {\n const now = new Date().toISOString();\n return {\n version: '1.0.0',\n created: now,\n updated: now,\n machine,\n files: {},\n };\n};\n","import { readFile, writeFile } from 'fs/promises';\nimport {\n tuckManifestSchema,\n createEmptyManifest,\n type TuckManifestOutput,\n type TrackedFileOutput,\n} from '../schemas/manifest.schema.js';\nimport { getManifestPath, pathExists } from './paths.js';\nimport { ManifestError } from '../errors.js';\n\nlet cachedManifest: TuckManifestOutput | null = null;\nlet cachedManifestDir: string | null = null;\n\nexport const loadManifest = async (tuckDir: string): Promise<TuckManifestOutput> => {\n // Return cached manifest if same directory\n if (cachedManifest && cachedManifestDir === tuckDir) {\n return cachedManifest;\n }\n\n const manifestPath = getManifestPath(tuckDir);\n\n if (!(await pathExists(manifestPath))) {\n throw new ManifestError('Manifest file not found. Is tuck initialized?');\n }\n\n try {\n const content = await readFile(manifestPath, 'utf-8');\n const rawManifest = JSON.parse(content);\n const result = tuckManifestSchema.safeParse(rawManifest);\n\n if (!result.success) {\n throw new ManifestError(`Invalid manifest: ${result.error.message}`);\n }\n\n cachedManifest = result.data;\n cachedManifestDir = tuckDir;\n\n return cachedManifest;\n } catch (error) {\n if (error instanceof ManifestError) {\n throw error;\n }\n if (error instanceof SyntaxError) {\n throw new ManifestError('Manifest file contains invalid JSON');\n }\n throw new ManifestError(`Failed to load manifest: ${error}`);\n }\n};\n\nexport const saveManifest = async (\n manifest: TuckManifestOutput,\n tuckDir: string\n): Promise<void> => {\n const manifestPath = getManifestPath(tuckDir);\n\n // Update the updated timestamp\n manifest.updated = new Date().toISOString();\n\n // Validate before saving\n const result = tuckManifestSchema.safeParse(manifest);\n if (!result.success) {\n throw new ManifestError(`Invalid manifest: ${result.error.message}`);\n }\n\n try {\n await writeFile(manifestPath, JSON.stringify(result.data, null, 2) + '\\n', 'utf-8');\n cachedManifest = result.data;\n cachedManifestDir = tuckDir;\n } catch (error) {\n throw new ManifestError(`Failed to save manifest: ${error}`);\n }\n};\n\nexport const createManifest = async (\n tuckDir: string,\n machine?: string\n): Promise<TuckManifestOutput> => {\n const manifestPath = getManifestPath(tuckDir);\n\n if (await pathExists(manifestPath)) {\n throw new ManifestError('Manifest already exists');\n }\n\n const manifest = createEmptyManifest(machine);\n\n try {\n await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8');\n cachedManifest = manifest;\n cachedManifestDir = tuckDir;\n return manifest;\n } catch (error) {\n throw new ManifestError(`Failed to create manifest: ${error}`);\n }\n};\n\nexport const addFileToManifest = async (\n tuckDir: string,\n id: string,\n file: TrackedFileOutput\n): Promise<void> => {\n const manifest = await loadManifest(tuckDir);\n\n if (manifest.files[id]) {\n throw new ManifestError(`File already tracked with ID: ${id}`);\n }\n\n manifest.files[id] = file;\n await saveManifest(manifest, tuckDir);\n};\n\nexport const updateFileInManifest = async (\n tuckDir: string,\n id: string,\n updates: Partial<TrackedFileOutput>\n): Promise<void> => {\n const manifest = await loadManifest(tuckDir);\n\n if (!manifest.files[id]) {\n throw new ManifestError(`File not found in manifest: ${id}`);\n }\n\n manifest.files[id] = {\n ...manifest.files[id],\n ...updates,\n modified: new Date().toISOString(),\n };\n\n await saveManifest(manifest, tuckDir);\n};\n\nexport const removeFileFromManifest = async (tuckDir: string, id: string): Promise<void> => {\n const manifest = await loadManifest(tuckDir);\n\n if (!manifest.files[id]) {\n throw new ManifestError(`File not found in manifest: ${id}`);\n }\n\n delete manifest.files[id];\n await saveManifest(manifest, tuckDir);\n};\n\nexport const getTrackedFile = async (\n tuckDir: string,\n id: string\n): Promise<TrackedFileOutput | null> => {\n const manifest = await loadManifest(tuckDir);\n return manifest.files[id] || null;\n};\n\nexport const getTrackedFileBySource = async (\n tuckDir: string,\n source: string\n): Promise<{ id: string; file: TrackedFileOutput } | null> => {\n const manifest = await loadManifest(tuckDir);\n\n for (const [id, file] of Object.entries(manifest.files)) {\n if (file.source === source) {\n return { id, file };\n }\n }\n\n return null;\n};\n\nexport const getAllTrackedFiles = async (\n tuckDir: string\n): Promise<Record<string, TrackedFileOutput>> => {\n const manifest = await loadManifest(tuckDir);\n return manifest.files;\n};\n\nexport const getTrackedFilesByCategory = async (\n tuckDir: string,\n category: string\n): Promise<Record<string, TrackedFileOutput>> => {\n const manifest = await loadManifest(tuckDir);\n const filtered: Record<string, TrackedFileOutput> = {};\n\n for (const [id, file] of Object.entries(manifest.files)) {\n if (file.category === category) {\n filtered[id] = file;\n }\n }\n\n return filtered;\n};\n\nexport const isFileTracked = async (tuckDir: string, source: string): Promise<boolean> => {\n const result = await getTrackedFileBySource(tuckDir, source);\n return result !== null;\n};\n\nexport const getFileCount = async (tuckDir: string): Promise<number> => {\n const manifest = await loadManifest(tuckDir);\n return Object.keys(manifest.files).length;\n};\n\nexport const getCategories = async (tuckDir: string): Promise<string[]> => {\n const manifest = await loadManifest(tuckDir);\n const categories = new Set<string>();\n\n for (const file of Object.values(manifest.files)) {\n categories.add(file.category);\n }\n\n return Array.from(categories).sort();\n};\n\nexport const clearManifestCache = (): void => {\n cachedManifest = null;\n cachedManifestDir = null;\n};\n","import simpleGit, { SimpleGit, StatusResult } from 'simple-git';\nimport { GitError } from '../errors.js';\nimport { pathExists } from './paths.js';\nimport { join } from 'path';\n\nexport interface GitStatus {\n isRepo: boolean;\n branch: string;\n tracking?: string;\n ahead: number;\n behind: number;\n staged: string[];\n modified: string[];\n untracked: string[];\n deleted: string[];\n hasChanges: boolean;\n}\n\nexport interface GitCommit {\n hash: string;\n date: string;\n message: string;\n author: string;\n}\n\nconst createGit = (dir: string): SimpleGit => {\n return simpleGit(dir, {\n binary: 'git',\n maxConcurrentProcesses: 6,\n trimmed: true,\n });\n};\n\nexport const isGitRepo = async (dir: string): Promise<boolean> => {\n const gitDir = join(dir, '.git');\n return pathExists(gitDir);\n};\n\nexport const initRepo = async (dir: string): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.init();\n } catch (error) {\n throw new GitError('Failed to initialize repository', String(error));\n }\n};\n\nexport const cloneRepo = async (url: string, dir: string): Promise<void> => {\n try {\n const git = simpleGit();\n await git.clone(url, dir);\n } catch (error) {\n throw new GitError(`Failed to clone repository from ${url}`, String(error));\n }\n};\n\nexport const addRemote = async (dir: string, name: string, url: string): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.addRemote(name, url);\n } catch (error) {\n throw new GitError('Failed to add remote', String(error));\n }\n};\n\nexport const removeRemote = async (dir: string, name: string): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.removeRemote(name);\n } catch (error) {\n throw new GitError('Failed to remove remote', String(error));\n }\n};\n\nexport const getRemotes = async (dir: string): Promise<{ name: string; url: string }[]> => {\n try {\n const git = createGit(dir);\n const remotes = await git.getRemotes(true);\n return remotes.map((r) => ({ name: r.name, url: r.refs.fetch || r.refs.push || '' }));\n } catch (error) {\n throw new GitError('Failed to get remotes', String(error));\n }\n};\n\nexport const getStatus = async (dir: string): Promise<GitStatus> => {\n try {\n const git = createGit(dir);\n const status: StatusResult = await git.status();\n\n return {\n isRepo: true,\n branch: status.current || 'main',\n tracking: status.tracking || undefined,\n ahead: status.ahead,\n behind: status.behind,\n staged: status.staged,\n modified: status.modified,\n untracked: status.not_added,\n deleted: status.deleted,\n hasChanges: !status.isClean(),\n };\n } catch (error) {\n throw new GitError('Failed to get status', String(error));\n }\n};\n\nexport const stageFiles = async (dir: string, files: string[]): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.add(files);\n } catch (error) {\n throw new GitError('Failed to stage files', String(error));\n }\n};\n\nexport const stageAll = async (dir: string): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.add('.');\n } catch (error) {\n throw new GitError('Failed to stage all files', String(error));\n }\n};\n\nexport const commit = async (dir: string, message: string): Promise<string> => {\n try {\n const git = createGit(dir);\n const result = await git.commit(message);\n return result.commit;\n } catch (error) {\n throw new GitError('Failed to commit', String(error));\n }\n};\n\n/**\n * Configure git to use gh CLI credentials if gh is authenticated\n */\nconst ensureGitCredentials = async (): Promise<void> => {\n try {\n // Check if gh is authenticated\n const { execFile } = await import('child_process');\n const { promisify } = await import('util');\n const execFileAsync = promisify(execFile);\n \n const { stdout, stderr } = await execFileAsync('gh', ['auth', 'status']);\n // gh auth status writes its output to stderr per gh CLI design\n const output = (stderr || stdout || '').trim();\n \n if (output.includes('Logged in')) {\n // gh is authenticated, configure git to use it\n await execFileAsync('gh', ['auth', 'setup-git']);\n }\n } catch {\n // gh CLI not available or not authenticated; skip git credential setup.\n // This is expected on systems without gh CLI or when user hasn't logged in.\n // Git will fall back to default credential mechanisms (ssh keys, https tokens, etc.)\n }\n};\n\nexport const push = async (\n dir: string,\n options?: { remote?: string; branch?: string; force?: boolean; setUpstream?: boolean }\n): Promise<void> => {\n try {\n // Ensure git can use gh credentials if available\n await ensureGitCredentials();\n \n const git = createGit(dir);\n const args: string[] = [];\n\n if (options?.setUpstream) {\n args.push('-u');\n }\n if (options?.force) {\n args.push('--force');\n }\n\n const remote = options?.remote || 'origin';\n const branch = options?.branch;\n\n if (branch) {\n await git.push([...args, remote, branch]);\n } else {\n await git.push([...args, remote]);\n }\n } catch (error) {\n throw new GitError('Failed to push', String(error));\n }\n};\n\nexport const pull = async (\n dir: string,\n options?: { remote?: string; branch?: string; rebase?: boolean }\n): Promise<void> => {\n try {\n const git = createGit(dir);\n const args: string[] = [];\n\n if (options?.rebase) {\n args.push('--rebase');\n }\n\n const remote = options?.remote || 'origin';\n const branch = options?.branch;\n\n if (branch) {\n await git.pull(remote, branch, args);\n } else {\n await git.pull(remote, undefined, args);\n }\n } catch (error) {\n throw new GitError('Failed to pull', String(error));\n }\n};\n\nexport const fetch = async (dir: string, remote = 'origin'): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.fetch(remote);\n } catch (error) {\n throw new GitError('Failed to fetch', String(error));\n }\n};\n\nexport const getLog = async (\n dir: string,\n options?: { maxCount?: number; since?: string }\n): Promise<GitCommit[]> => {\n try {\n const git = createGit(dir);\n const logOptions: { maxCount?: number; from?: string } = {\n maxCount: options?.maxCount || 10,\n };\n\n if (options?.since) {\n logOptions.from = options.since;\n }\n\n const log = await git.log(logOptions);\n\n return log.all.map((entry) => ({\n hash: entry.hash,\n date: entry.date,\n message: entry.message,\n author: entry.author_name || 'Unknown',\n }));\n } catch (error) {\n throw new GitError('Failed to get log', String(error));\n }\n};\n\nexport const getDiff = async (\n dir: string,\n options?: { staged?: boolean; stat?: boolean; files?: string[] }\n): Promise<string> => {\n try {\n const git = createGit(dir);\n const args: string[] = [];\n\n if (options?.staged) {\n args.push('--staged');\n }\n if (options?.stat) {\n args.push('--stat');\n }\n if (options?.files) {\n args.push('--');\n args.push(...options.files);\n }\n\n const result = await git.diff(args);\n return result;\n } catch (error) {\n throw new GitError('Failed to get diff', String(error));\n }\n};\n\nexport const getCurrentBranch = async (dir: string): Promise<string> => {\n try {\n const git = createGit(dir);\n const branch = await git.revparse(['--abbrev-ref', 'HEAD']);\n return branch.trim();\n } catch {\n // Fallback for repos with no commits - read symbolic-ref directly\n try {\n const git = createGit(dir);\n const ref = await git.raw(['symbolic-ref', '--short', 'HEAD']);\n return ref.trim();\n } catch {\n // Last resort - return default branch name\n return 'main';\n }\n }\n};\n\nexport const hasRemote = async (dir: string, name = 'origin'): Promise<boolean> => {\n try {\n const remotes = await getRemotes(dir);\n return remotes.some((r) => r.name === name);\n } catch {\n return false;\n }\n};\n\nexport const getRemoteUrl = async (dir: string, name = 'origin'): Promise<string | null> => {\n try {\n const remotes = await getRemotes(dir);\n const remote = remotes.find((r) => r.name === name);\n return remote?.url || null;\n } catch {\n return null;\n }\n};\n\nexport const setDefaultBranch = async (dir: string, branch: string): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.branch(['-M', branch]);\n } catch (error) {\n throw new GitError('Failed to set default branch', String(error));\n }\n};\n","import { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport { GitHubCliError } from '../errors.js';\n\nconst execFileAsync = promisify(execFile);\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** API request timeout in milliseconds (10 seconds) */\nconst API_REQUEST_TIMEOUT_MS = 10000;\n\n/**\n * Git credential helper fallback cache timeout in seconds (24 hours).\n * This is used when the git credential helper falls back to cache mode on Linux.\n */\nconst GIT_CREDENTIAL_CACHE_FALLBACK_TIMEOUT_SECONDS = 86400;\n\n/** Days threshold for warning about potentially expired tokens (85 days, before typical 90-day expiration) */\nconst TOKEN_EXPIRATION_WARNING_DAYS = 85;\n\n/** Minimum length for a valid GitHub token */\nexport const MIN_GITHUB_TOKEN_LENGTH = 20;\n\n/**\n * Valid GitHub token prefixes for validation purposes.\n * Note: detectTokenType() only distinguishes between fine-grained (github_pat_)\n * and classic (ghp_) tokens, but GitHub issues other token types that should\n * still be accepted as valid (gho_, ghu_, ghs_, ghr_).\n */\nexport const GITHUB_TOKEN_PREFIXES = [\n 'github_pat_', // Fine-grained PAT\n 'ghp_', // Classic PAT\n 'gho_', // OAuth token\n 'ghu_', // User token\n 'ghs_', // Server token\n 'ghr_', // Refresh token\n] as const;\n\n/**\n * Validate repository name/identifier to prevent command injection.\n * Valid formats: \"owner/repo\", \"repo\", or full URLs\n */\nconst validateRepoName = (repoName: string): void => {\n // Allow full URLs (https:// or git@)\n if (repoName.includes('://') || repoName.startsWith('git@')) {\n // Basic URL validation - must not contain shell metacharacters\n if (/[;&|`$(){}[\\]<>!#*?]/.test(repoName.replace(/[/:@.]/g, ''))) {\n throw new GitHubCliError(`Invalid repository URL: ${repoName}`);\n }\n return;\n }\n\n // For owner/repo or repo format, validate strictly\n // Valid: alphanumeric, hyphens, underscores, dots, and single forward slash\n const validPattern = /^[a-zA-Z0-9._-]+(?:\\/[a-zA-Z0-9._-]+)?$/;\n if (!validPattern.test(repoName)) {\n throw new GitHubCliError(`Invalid repository name: ${repoName}`, [\n 'Repository names can only contain alphanumeric characters, hyphens, underscores, and dots',\n 'Format: \"owner/repo\" or \"repo\"',\n ]);\n }\n};\n\nexport interface GitHubUser {\n login: string;\n name: string | null;\n email: string | null;\n}\n\nexport interface GitHubRepo {\n name: string;\n fullName: string;\n url: string;\n sshUrl: string;\n httpsUrl: string;\n isPrivate: boolean;\n}\n\nexport interface CreateRepoOptions {\n name: string;\n description?: string;\n isPrivate?: boolean;\n homepage?: string;\n}\n\n/**\n * Check if the GitHub CLI (gh) is installed\n */\nexport const isGhInstalled = async (): Promise<boolean> => {\n try {\n await execFileAsync('gh', ['--version']);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Check if the user is authenticated with GitHub CLI\n */\nexport const isGhAuthenticated = async (): Promise<boolean> => {\n try {\n // gh auth status outputs to stderr, not stdout\n // execFileAsync provides both stdout and stderr even on success\n const { stdout, stderr } = await execFileAsync('gh', ['auth', 'status']);\n // Check stderr (where gh auth status outputs) and stdout (as fallback)\n const output = (stderr || stdout || '').trim();\n // Only return true if we can definitively confirm authentication\n // Check for positive indicator, not absence of negative indicator\n return output.includes('Logged in');\n } catch (error) {\n // gh auth status returns exit code 1 when not authenticated\n // and outputs error message to stderr\n if (error instanceof Error && 'stderr' in error) {\n const stderr = (error as { stderr: string }).stderr;\n // Only return true if stderr explicitly confirms authentication\n return stderr.includes('Logged in');\n }\n return false;\n }\n};\n\n/**\n * Get the authenticated GitHub user's information\n */\nexport const getAuthenticatedUser = async (): Promise<GitHubUser> => {\n if (!(await isGhInstalled())) {\n throw new GitHubCliError('GitHub CLI is not installed');\n }\n\n if (!(await isGhAuthenticated())) {\n throw new GitHubCliError('Not authenticated with GitHub CLI', [\n 'Run `gh auth login` to authenticate',\n ]);\n }\n\n try {\n const { stdout } = await execFileAsync('gh', ['api', 'user', '--jq', '.login, .name, .email']);\n const lines = stdout.trim().split('\\n');\n return {\n login: lines[0] || '',\n name: lines[1] !== 'null' ? lines[1] : null,\n email: lines[2] !== 'null' ? lines[2] : null,\n };\n } catch (error) {\n throw new GitHubCliError('Failed to get user information', [\n String(error),\n 'Check your GitHub CLI authentication',\n ]);\n }\n};\n\n/**\n * Check if a repository exists on GitHub\n */\nexport const repoExists = async (repoName: string): Promise<boolean> => {\n try {\n validateRepoName(repoName);\n await execFileAsync('gh', ['repo', 'view', repoName, '--json', 'name']);\n return true;\n } catch {\n return false;\n }\n};\n\ninterface RepoCreationDiagnosis {\n reason: string;\n suggestions: string[];\n}\n\n/**\n * Diagnose why repository creation failed and provide helpful suggestions\n */\nconst diagnoseRepoCreationFailure = async (\n repoName: string,\n errorMessage: string\n): Promise<RepoCreationDiagnosis> => {\n const errorLower = errorMessage.toLowerCase();\n\n // Check if repo already exists (double-check in case of race condition)\n try {\n const user = await getAuthenticatedUser();\n const fullName = `${user.login}/${repoName}`;\n if (await repoExists(fullName)) {\n return {\n reason: `Repository \"${fullName}\" already exists`,\n suggestions: [\n `Use the existing repository: tuck init --from ${fullName}`,\n `Delete it first at github.com/${fullName}/settings`,\n 'Choose a different name for your dotfiles repository',\n ],\n };\n }\n } catch {\n // Ignore - continue with other checks\n }\n\n // Permission errors\n if (errorLower.includes('permission') || errorLower.includes('forbidden') || errorLower.includes('403')) {\n return {\n reason: 'Insufficient permissions to create repository',\n suggestions: [\n 'Check your GitHub CLI authentication: gh auth status',\n 'Re-authenticate with repo scope: gh auth login --scopes repo',\n 'Create the repository manually at github.com/new',\n ],\n };\n }\n\n // Name already taken (in an org or different context)\n if (errorLower.includes('name already exists') || errorLower.includes('already exists')) {\n return {\n reason: `Repository name \"${repoName}\" is already taken`,\n suggestions: [\n 'Choose a different name (e.g., \"my-dotfiles\", \"dotfiles-backup\")',\n 'Check if you already have this repository: gh repo list',\n 'Create the repository manually at github.com/new',\n ],\n };\n }\n\n // Rate limiting\n if (errorLower.includes('rate limit') || errorLower.includes('429') || errorLower.includes('too many')) {\n return {\n reason: 'GitHub API rate limit exceeded',\n suggestions: [\n 'Wait a few minutes and try again',\n 'Create the repository manually at github.com/new',\n ],\n };\n }\n\n // Network issues\n if (\n errorLower.includes('network') ||\n errorLower.includes('enotfound') ||\n errorLower.includes('timeout') ||\n errorLower.includes('econnrefused')\n ) {\n return {\n reason: 'Network error - could not reach GitHub',\n suggestions: [\n 'Check your internet connection',\n 'Try again in a moment',\n 'Create the repository manually at github.com/new',\n ],\n };\n }\n\n // Authentication expired or invalid\n if (errorLower.includes('401') || errorLower.includes('unauthorized') || errorLower.includes('bad credentials')) {\n return {\n reason: 'GitHub authentication expired or invalid',\n suggestions: [\n 'Re-authenticate: gh auth login',\n 'Check your token: gh auth status',\n ],\n };\n }\n\n // Generic fallback with manual instructions\n return {\n reason: `Failed to create repository \"${repoName}\"`,\n suggestions: [\n 'Create the repository manually:',\n ' 1. Go to github.com/new',\n ` 2. Name: ${repoName}`,\n ' 3. Visibility: Private (recommended)',\n ' 4. Do NOT initialize with README/.gitignore',\n ' 5. Click \"Create repository\"',\n ' 6. Copy the URL and paste when prompted',\n ],\n };\n};\n\n/**\n * Create a new GitHub repository\n */\nexport const createRepo = async (options: CreateRepoOptions): Promise<GitHubRepo> => {\n if (!(await isGhInstalled())) {\n throw new GitHubCliError('GitHub CLI is not installed');\n }\n\n if (!(await isGhAuthenticated())) {\n throw new GitHubCliError('Not authenticated with GitHub CLI', [\n 'Run `gh auth login` to authenticate',\n ]);\n }\n\n // Check if repo already exists\n const user = await getAuthenticatedUser();\n const fullName = `${user.login}/${options.name}`;\n\n if (await repoExists(fullName)) {\n throw new GitHubCliError(`Repository \"${fullName}\" already exists`, [\n `Use a different name or run \\`tuck init --remote ${fullName}\\``,\n ]);\n }\n\n // Validate inputs to prevent command injection\n validateRepoName(options.name);\n \n if (options.description && /[;&|`$(){}[\\]<>!#*?]/.test(options.description)) {\n throw new GitHubCliError('Invalid description: contains unsafe characters');\n }\n \n if (options.homepage && /[;&|`$(){}[\\]<>!#*?]/.test(options.homepage)) {\n throw new GitHubCliError('Invalid homepage: contains unsafe characters');\n }\n\n try {\n // Build command arguments array to prevent command injection\n const args: string[] = ['repo', 'create', options.name];\n \n if (options.isPrivate !== false) {\n args.push('--private');\n } else {\n args.push('--public');\n }\n \n if (options.description) {\n args.push('--description', options.description);\n }\n \n if (options.homepage) {\n args.push('--homepage', options.homepage);\n }\n \n args.push('--confirm', '--json', 'name,url,sshUrl');\n \n const { stdout } = await execFileAsync('gh', args);\n const result = JSON.parse(stdout);\n\n return {\n name: result.name,\n fullName: `${user.login}/${result.name}`,\n url: result.url,\n sshUrl: result.sshUrl,\n httpsUrl: result.url.replace('github.com', 'github.com').replace(/^https?:\\/\\//, 'https://'),\n isPrivate: options.isPrivate !== false,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const diagnosis = await diagnoseRepoCreationFailure(options.name, errorMessage);\n throw new GitHubCliError(diagnosis.reason, diagnosis.suggestions);\n }\n};\n\n/**\n * Get the preferred remote URL format (SSH or HTTPS)\n */\nexport const getPreferredRemoteProtocol = async (): Promise<'ssh' | 'https'> => {\n try {\n const { stdout } = await execFileAsync('gh', ['config', 'get', 'git_protocol']);\n const protocol = stdout.trim().toLowerCase();\n return protocol === 'ssh' ? 'ssh' : 'https';\n } catch {\n // Default to HTTPS if we can't determine preference\n return 'https';\n }\n};\n\n/**\n * Get repository information from GitHub\n */\nexport const getRepoInfo = async (repoName: string): Promise<GitHubRepo | null> => {\n try {\n validateRepoName(repoName);\n const { stdout } = await execFileAsync('gh', [\n 'repo',\n 'view',\n repoName,\n '--json',\n 'name,url,sshUrl,isPrivate,owner',\n ]);\n const result = JSON.parse(stdout);\n\n return {\n name: result.name,\n fullName: `${result.owner.login}/${result.name}`,\n url: result.url,\n sshUrl: result.sshUrl,\n httpsUrl: result.url,\n isPrivate: result.isPrivate,\n };\n } catch {\n return null;\n }\n};\n\n/**\n * Clone a repository to a specific directory using gh CLI\n */\nexport const ghCloneRepo = async (repoName: string, targetDir: string): Promise<void> => {\n if (!(await isGhInstalled())) {\n throw new GitHubCliError('GitHub CLI is not installed');\n }\n\n validateRepoName(repoName);\n\n try {\n await execFileAsync('gh', ['repo', 'clone', repoName, targetDir]);\n } catch (error) {\n throw new GitHubCliError(`Failed to clone repository \"${repoName}\"`, [\n String(error),\n 'Check that the repository exists and you have access',\n ]);\n }\n};\n\n/**\n * Find a user's dotfiles repository (checks common names)\n */\nexport const findDotfilesRepo = async (username?: string): Promise<string | null> => {\n const user = username || (await getAuthenticatedUser()).login;\n const commonNames = ['dotfiles', 'tuck', '.dotfiles', 'dot-files', 'dots'];\n\n for (const name of commonNames) {\n const repoName = `${user}/${name}`;\n if (await repoExists(repoName)) {\n return repoName;\n }\n }\n\n return null;\n};\n\n/**\n * Get the remote URL in the user's preferred format (SSH or HTTPS)\n */\nexport const getPreferredRepoUrl = async (repo: GitHubRepo): Promise<string> => {\n const protocol = await getPreferredRemoteProtocol();\n return protocol === 'ssh' ? repo.sshUrl : repo.httpsUrl;\n};\n\n// ============================================================================\n// Alternative Authentication Methods (when GitHub CLI is not available)\n// ============================================================================\n\nexport interface SSHKeyInfo {\n exists: boolean;\n path: string;\n publicKeyPath: string;\n publicKey?: string;\n}\n\n/**\n * Check if SSH keys exist for GitHub\n */\nexport const checkSSHKeys = async (): Promise<SSHKeyInfo> => {\n const { homedir } = await import('os');\n const { join } = await import('path');\n const { readFile } = await import('fs/promises');\n const { pathExists } = await import('./paths.js');\n\n const sshDir = join(homedir(), '.ssh');\n const keyTypes = ['id_ed25519', 'id_rsa', 'id_ecdsa'];\n\n for (const keyType of keyTypes) {\n const privateKeyPath = join(sshDir, keyType);\n const publicKeyPath = `${privateKeyPath}.pub`;\n\n if (await pathExists(publicKeyPath)) {\n try {\n const publicKey = await readFile(publicKeyPath, 'utf-8');\n return {\n exists: true,\n path: privateKeyPath,\n publicKeyPath,\n publicKey: publicKey.trim(),\n };\n } catch {\n return {\n exists: true,\n path: privateKeyPath,\n publicKeyPath,\n };\n }\n }\n }\n\n return {\n exists: false,\n path: join(sshDir, 'id_ed25519'),\n publicKeyPath: join(sshDir, 'id_ed25519.pub'),\n };\n};\n\n/**\n * Determine the appropriate StrictHostKeyChecking option for GitHub SSH tests.\n * Uses \"yes\" if github.com is already in known_hosts, otherwise \"accept-new\".\n */\nconst getStrictHostKeyCheckingOption = async (): Promise<string> => {\n try {\n const { homedir } = await import('os');\n const { join } = await import('path');\n const { readFile } = await import('fs/promises');\n\n const sshDir = join(homedir(), '.ssh');\n const knownHostsPath = join(sshDir, 'known_hosts');\n\n const knownHostsContent = await readFile(knownHostsPath, 'utf-8');\n\n // Check if github.com already has a plain-text entry by looking for lines that start with 'github.com'\n // Note: We don't check hashed entries (|1|...) because we can't verify the hostname without\n // attempting the SSH connection. For security purposes, we only trust explicit github.com entries.\n // Format: \"github.com[,port] key-type key-data [comment]\" or \"@marker github.com[,port] key-type...\"\n const hasGitHubEntry = knownHostsContent.split('\\n').some(line => {\n const trimmed = line.trim();\n // Skip comments and empty lines\n if (!trimmed || trimmed.startsWith('#')) return false;\n \n // Handle @marker entries (e.g., @cert-authority or @revoked)\n const hostnamePart = trimmed.startsWith('@') \n ? trimmed.split(/\\s+/)[1] // Get second field after marker\n : trimmed.split(/\\s+/)[0]; // Get first field for regular entries\n \n // Check for exact hostname match (github.com or github.com,port)\n if (!hostnamePart) return false;\n return hostnamePart === 'github.com' || hostnamePart.startsWith('github.com,');\n });\n\n if (hasGitHubEntry) {\n return 'yes';\n }\n } catch {\n // If known_hosts doesn't exist or can't be read, fall back to accept-new\n // to preserve existing behavior for first-time setups.\n }\n\n // Use accept-new for better UX on first connection. This will automatically\n // trust a new host key, which can weaken protection against MITM attacks during\n // initial key establishment. However, since the target is hard-coded to github.com,\n // whose SSH host keys are well-known and documented, the practical risk is low.\n return 'accept-new';\n};\n\n/**\n * Test if SSH connection to GitHub works\n */\nexport const testSSHConnection = async (): Promise<{ success: boolean; username?: string }> => {\n try {\n const strictHostKeyChecking = await getStrictHostKeyCheckingOption();\n // ssh -T git@github.com returns exit code 1 even on success, but outputs the username\n const { stderr } = await execFileAsync('ssh', ['-T', '-o', `StrictHostKeyChecking=${strictHostKeyChecking}`, 'git@github.com']);\n const match = stderr.match(/Hi ([^!]+)!/);\n if (match) {\n return { success: true, username: match[1] };\n }\n return { success: false };\n } catch (error) {\n // SSH returns exit code 1 even on successful auth, check stderr for success message\n if (error instanceof Error && 'stderr' in error) {\n const stderr = (error as { stderr: string }).stderr;\n const match = stderr.match(/Hi ([^!]+)!/);\n if (match) {\n return { success: true, username: match[1] };\n }\n }\n return { success: false };\n }\n};\n\n/**\n * Get instructions for generating SSH keys\n */\nexport const getSSHKeyInstructions = (email?: string): string => {\n const emailFlag = email ? ` -C \"${email}\"` : '';\n\n return `\nTo set up SSH authentication with GitHub:\n\n1. Generate a new SSH key (recommended: Ed25519):\n ssh-keygen -t ed25519${emailFlag}\n\n Press Enter to accept the default file location\n Enter a passphrase (recommended) or press Enter for none\n\n2. Start the SSH agent:\n eval \"$(ssh-agent -s)\"\n\n3. Add your SSH key to the agent:\n ssh-add ~/.ssh/id_ed25519\n\n4. Copy your public key:\n - macOS: pbcopy < ~/.ssh/id_ed25519.pub\n - Linux: cat ~/.ssh/id_ed25519.pub\n\n5. Add the key to GitHub:\n - Go to: https://github.com/settings/ssh/new\n - Title: Your computer name (e.g., \"MacBook Pro\")\n - Key type: Authentication Key\n - Key: Paste your public key\n - Click \"Add SSH key\"\n\n6. Test the connection:\n ssh -T git@github.com\n\n You should see: \"Hi username! You've successfully authenticated...\"\n`.trim();\n};\n\n/**\n * Get instructions for creating a fine-grained personal access token\n */\nexport const getFineGrainedTokenInstructions = (repoName?: string): string => {\n return `\nTo create a Fine-grained Personal Access Token (recommended):\n\n1. Go to: https://github.com/settings/tokens?type=beta\n\n2. Click \"Generate new token\"\n\n3. Configure the token:\n - Token name: \"tuck-dotfiles\" (or any descriptive name)\n - Expiration: 90 days (or custom, can be renewed)\n - Description: \"Token for tuck dotfiles manager\"\n\n4. Repository access:\n - Select \"Only select repositories\"\n - Choose your dotfiles repository${repoName ? ` (${repoName})` : ''}\n - Or select \"All repositories\" if you haven't created it yet\n\n5. Permissions needed (under \"Repository permissions\"):\n ┌─────────────────────────┬─────────────────┐\n │ Permission │ Access Level │\n ├─────────────────────────┼─────────────────┤\n │ Contents │ Read and write │\n │ Metadata │ Read-only │\n └─────────────────────────┴─────────────────┘\n\n That's it! Only 2 permissions needed.\n\n6. Click \"Generate token\"\n\n7. IMPORTANT: Copy the token immediately!\n It won't be shown again.\n\n8. Configure git to use the token:\n When pushing, use this as your password:\n - Username: your-github-username\n - Password: github_pat_xxxxxxxxxxxx (your token)\n\n Or configure credential storage:\n git config --global credential.helper store\n\n Then on first push, enter your token as the password\n and it will be saved for future use.\n`.trim();\n};\n\n/**\n * Get instructions for creating a classic personal access token\n */\nexport const getClassicTokenInstructions = (): string => {\n return `\nTo create a Classic Personal Access Token:\n\nNote: Fine-grained tokens are recommended for better security,\nbut classic tokens work if you need broader access.\n\n1. Go to: https://github.com/settings/tokens/new\n\n2. Configure the token:\n - Note: \"tuck-dotfiles\" (or any descriptive name)\n - Expiration: 90 days (or \"No expiration\" - less secure)\n\n3. Select scopes (permissions):\n ┌─────────────────────────┬─────────────────────────────────────┐\n │ Scope │ Why it's needed │\n ├─────────────────────────┼─────────────────────────────────────┤\n │ ☑ repo │ Full access to private repositories │\n │ ☑ repo:status │ Access commit status │\n │ ☑ repo_deployment │ Access deployment status │\n │ ☑ public_repo │ Access public repositories │\n │ ☑ repo:invite │ Access repository invitations │\n └─────────────────────────┴─────────────────────────────────────┘\n\n Just check the top-level \"repo\" box - it selects all sub-items.\n\n4. Click \"Generate token\"\n\n5. IMPORTANT: Copy the token immediately!\n It starts with \"ghp_\" and won't be shown again.\n\n6. Configure git to use the token:\n When pushing, use this as your password:\n - Username: your-github-username\n - Password: ghp_xxxxxxxxxxxx (your token)\n\n Or configure credential storage:\n git config --global credential.helper store\n\n Then on first push, enter your token as the password.\n`.trim();\n};\n\n/**\n * Get instructions for installing GitHub CLI\n */\nexport const getGitHubCLIInstallInstructions = (): string => {\n const { platform } = process;\n\n let installCmd = '';\n if (platform === 'darwin') {\n installCmd = 'brew install gh';\n } else if (platform === 'linux') {\n installCmd = `# Debian/Ubuntu:\nsudo apt install gh\n\n# Fedora:\nsudo dnf install gh\n\n# Arch Linux:\nsudo pacman -S github-cli`;\n } else if (platform === 'win32') {\n installCmd = `# Using winget:\nwinget install GitHub.cli\n\n# Using scoop:\nscoop install gh\n\n# Using chocolatey:\nchoco install gh`;\n }\n\n return `\nGitHub CLI (gh) - Recommended for the best experience\n\nThe GitHub CLI provides the easiest authentication and\nlets tuck automatically create repositories for you.\n\nInstallation:\n${installCmd}\n\nAfter installing, authenticate:\ngh auth login\n\nBenefits:\n- Automatic repository creation\n- No manual token management\n- Easy authentication refresh\n- Works with SSH or HTTPS\n\nLearn more: https://cli.github.com/\n`.trim();\n};\n\nexport type AuthMethod = 'gh-cli' | 'ssh' | 'fine-grained-token' | 'classic-token';\n\nexport interface AuthMethodInfo {\n id: AuthMethod;\n name: string;\n description: string;\n recommended: boolean;\n instructions: string;\n}\n\n/**\n * Get all available authentication methods with instructions\n */\nexport const getAuthMethods = (repoName?: string, email?: string): AuthMethodInfo[] => {\n return [\n {\n id: 'gh-cli',\n name: 'GitHub CLI (gh)',\n description: 'Easiest option - automatic repo creation, no token management',\n recommended: true,\n instructions: getGitHubCLIInstallInstructions(),\n },\n {\n id: 'ssh',\n name: 'SSH Key',\n description: 'Secure, no password needed after setup, works everywhere',\n recommended: false,\n instructions: getSSHKeyInstructions(email),\n },\n {\n id: 'fine-grained-token',\n name: 'Fine-grained Token',\n description: 'Limited permissions, more secure, repository-specific',\n recommended: false,\n instructions: getFineGrainedTokenInstructions(repoName),\n },\n {\n id: 'classic-token',\n name: 'Classic Token',\n description: 'Broader access, simpler setup, works with all repos',\n recommended: false,\n instructions: getClassicTokenInstructions(),\n },\n ];\n};\n\n/**\n * Configure git credential helper for HTTPS authentication\n */\nexport const configureGitCredentialHelper = async (): Promise<void> => {\n const { platform } = process;\n\n // Check if a credential helper is already configured\n try {\n const { stdout } = await execFileAsync('git', ['config', '--global', 'credential.helper']);\n if (stdout.trim()) {\n // User already has a credential helper configured, don't override it\n return;\n }\n } catch {\n // No credential helper configured, proceed with setup\n }\n\n try {\n if (platform === 'darwin') {\n // macOS - use Keychain\n await execFileAsync('git', ['config', '--global', 'credential.helper', 'osxkeychain']);\n } else if (platform === 'linux') {\n // Linux - use libsecret if available, otherwise cache\n try {\n await execFileAsync('git', ['config', '--global', 'credential.helper', 'libsecret']);\n } catch (error) {\n console.info(\n 'git-credential-libsecret is not available; falling back to git credential cache helper with timeout of ' +\n `${GIT_CREDENTIAL_CACHE_FALLBACK_TIMEOUT_SECONDS} seconds.`\n );\n await execFileAsync('git', ['config', '--global', 'credential.helper', `cache --timeout=${GIT_CREDENTIAL_CACHE_FALLBACK_TIMEOUT_SECONDS}`]);\n }\n } else if (platform === 'win32') {\n // Windows - use credential manager\n await execFileAsync('git', ['config', '--global', 'credential.helper', 'manager']);\n }\n } catch {\n // Fallback to store (less secure but works everywhere)\n await execFileAsync('git', ['config', '--global', 'credential.helper', 'store']);\n }\n};\n\n// ============================================================================\n// Secure Credential Management\n// ============================================================================\n\nexport interface StoredCredential {\n username: string;\n token: string;\n createdAt: string;\n type: 'fine-grained' | 'classic';\n}\n\n/**\n * Get the path to the tuck credentials file\n */\nconst getCredentialsPath = async (): Promise<string> => {\n const { homedir } = await import('os');\n const { join } = await import('path');\n return join(homedir(), '.tuck', '.credentials.json');\n};\n\n/**\n * Store GitHub credentials securely\n * Uses git credential helper for the actual token storage\n * Stores metadata (type, creation date) in tuck config\n */\nexport const storeGitHubCredentials = async (\n username: string,\n token: string,\n type: 'fine-grained' | 'classic'\n): Promise<void> => {\n const { writeFile, mkdir } = await import('fs/promises');\n const { dirname } = await import('path');\n\n // First, configure the credential helper\n await configureGitCredentialHelper();\n\n // Validate that username and token do not contain newline characters,\n // which would break the git credential helper protocol format.\n if (/[\\r\\n]/.test(username) || /[\\r\\n]/.test(token)) {\n throw new GitHubCliError('Username or token contains invalid newline characters.', [\n \"Newline characters are not allowed in GitHub usernames or tokens because git's credential helper protocol is line-based.\",\n 'Each credential field is sent as \"key=value\" on its own line; embedded newlines would corrupt this format and cause git credential storage to fail.',\n 'If you copied the token from a password manager or web page, ensure it is a single line with no trailing line breaks, then paste it again or regenerate a new token.',\n ]);\n }\n\n // Store the credential using git credential helper\n // This pipes the credential to git credential approve\n const credentialInput = `protocol=https\\nhost=github.com\\nusername=${username}\\npassword=${token}\\n\\n`; // Note: git credential protocol requires input to be terminated with a blank line (\\n\\n)\n\n try {\n const { spawn } = await import('child_process');\n await new Promise<void>((resolve, reject) => {\n const proc = spawn('git', ['credential', 'approve'], {\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n proc.stdin.write(credentialInput);\n proc.stdin.end();\n\n proc.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error('git credential approve failed'));\n }\n });\n\n proc.on('error', reject);\n });\n } catch (error) {\n // If git credential helper fails, we can still continue.\n // The user will just be prompted for credentials on push.\n const warningMessage =\n 'Failed to store GitHub credentials via `git credential approve`. ' +\n 'Credentials will not be cached and you may be prompted again on push.';\n\n // Emit a process warning so this is visible in a non-blocking way.\n try {\n process.emitWarning(warningMessage, {\n code: 'GIT_CREDENTIAL_HELPER_FAILED',\n });\n } catch {\n // Fallback: emitting a warning should never break the main flow.\n }\n\n // Also log to console for environments that rely on standard output logging.\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n console.warn(`Warning: ${warningMessage} Error: ${errorMessage}`);\n }\n\n // Store metadata (not the token itself) for expiration tracking\n const credentialsPath = await getCredentialsPath();\n const metadata = {\n username,\n type,\n createdAt: new Date().toISOString(),\n // Don't store the actual token - just track that we have one\n hasToken: true,\n };\n\n try {\n await mkdir(dirname(credentialsPath), { recursive: true });\n // Note: File permissions (0o600) protect this metadata file on the filesystem,\n // but the username stored in this file is in plaintext and may be readable by\n // any process running as the same OS user. Only non-secret metadata such as\n // the username and token presence/creation time are stored here; the actual\n // token is stored securely via the git credential helper (e.g., osxkeychain,\n // libsecret, manager) which uses OS-level secure storage. The security of the\n // token itself depends on the credential helper implementation, not this file.\n await writeFile(credentialsPath, JSON.stringify(metadata, null, 2), {\n mode: 0o600, // Read/write only for owner\n });\n } catch (error) {\n // Non-critical - metadata storage failed, but surface a warning as this affects\n // security-relevant file permissions/metadata and token expiration tracking.\n const warningMessage =\n `Failed to store GitHub credential metadata at \"${credentialsPath}\". ` +\n 'Token expiration tracking and verification of restricted file permissions ' +\n '(0o600) may not work as expected.';\n\n // Emit a process warning so this is visible to the user in a non-blocking way.\n try {\n process.emitWarning(warningMessage, {\n code: 'GITHUB_CREDENTIAL_METADATA_WRITE_FAILED',\n });\n } catch {\n // Fallback: emitting a warning should never break the main flow.\n }\n\n // Also log to console for environments that rely on standard output logging,\n // but avoid exposing full filesystem paths by default. Detailed information,\n // including the credential metadata path and underlying error, is only logged\n // when an explicit debug flag is enabled.\n const isDebugLoggingEnabled =\n process.env.GITHUB_DEBUG_CREDENTIALS_METADATA === '1';\n if (isDebugLoggingEnabled) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n console.warn(\n `Warning: ${warningMessage} Error: ${errorMessage}`,\n );\n } else {\n console.warn(\n 'Warning: Failed to store GitHub credential metadata. ' +\n 'Token expiration tracking and verification of restricted file ' +\n 'permissions (0o600) may not work as expected.',\n );\n }\n }\n};\n\n/**\n * Get stored credential metadata\n */\nexport const getStoredCredentialMetadata = async (): Promise<{\n username?: string;\n type?: 'fine-grained' | 'classic';\n createdAt?: Date;\n hasToken?: boolean;\n} | null> => {\n const { readFile } = await import('fs/promises');\n const { pathExists } = await import('./paths.js');\n\n const credentialsPath = await getCredentialsPath();\n\n if (!(await pathExists(credentialsPath))) {\n return null;\n }\n\n try {\n const content = await readFile(credentialsPath, 'utf-8');\n const data = JSON.parse(content);\n return {\n username: data.username,\n type: data.type,\n createdAt: data.createdAt ? new Date(data.createdAt) : undefined,\n hasToken: data.hasToken,\n };\n } catch {\n return null;\n }\n};\n\n/**\n * Remove stored credentials (both from git helper and metadata)\n */\nexport const removeStoredCredentials = async (): Promise<void> => {\n const { unlink } = await import('fs/promises');\n const { pathExists } = await import('./paths.js');\n\n // Remove from git credential helper\n try {\n const { spawn } = await import('child_process');\n await new Promise<void>((resolve) => {\n const proc = spawn('git', ['credential', 'reject'], {\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n // Note: git credential protocol requires input to be terminated with a blank line (\\n\\n)\n proc.stdin.write('protocol=https\\nhost=github.com\\n\\n');\n proc.stdin.end();\n\n proc.on('close', () => resolve());\n proc.on('error', () => resolve());\n });\n } catch {\n // Ignore errors\n }\n\n // Remove metadata file\n const credentialsPath = await getCredentialsPath();\n if (await pathExists(credentialsPath)) {\n try {\n await unlink(credentialsPath);\n } catch {\n // Ignore errors\n }\n }\n};\n\n/**\n * Test if stored credentials are still valid\n * Uses GitHub API /user endpoint which requires authentication\n */\nexport const testStoredCredentials = async (): Promise<{\n valid: boolean;\n reason?: 'expired' | 'invalid' | 'network' | 'unknown';\n username?: string;\n}> => {\n const metadata = await getStoredCredentialMetadata();\n\n if (!metadata?.hasToken) {\n return { valid: false, reason: 'unknown' };\n }\n\n // Get credentials from git credential helper\n let username: string | null = null;\n let password: string | null = null;\n\n try {\n const { spawn } = await import('child_process');\n const credentialOutput = await new Promise<string>((resolve, reject) => {\n const proc = spawn('git', ['credential', 'fill'], {\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n // Request credentials for github.com\n proc.stdin.write('protocol=https\\nhost=github.com\\n\\n');\n proc.stdin.end();\n\n let output = '';\n proc.stdout.on('data', (data) => {\n output += data.toString();\n });\n\n proc.on('close', (code) => {\n if (code === 0) {\n resolve(output);\n } else {\n reject(new Error('git credential fill failed'));\n }\n });\n\n proc.on('error', reject);\n });\n\n // Parse credential output (format: key=value\\n). Values may contain '=' characters,\n // so split into at most two parts: key and the full remaining value.\n for (const line of credentialOutput.trim().split('\\n')) {\n const [key, value] = line.split('=', 2);\n if (value === undefined) {\n continue;\n }\n if (key === 'username') {\n username = value;\n } else if (key === 'password') {\n password = value;\n }\n }\n } catch {\n // If we can't get credentials, they're not valid\n return { valid: false, reason: 'unknown', username: metadata.username };\n }\n\n if (!username || !password) {\n return { valid: false, reason: 'unknown', username: metadata.username };\n }\n\n // Test credentials against GitHub API /user endpoint (requires authentication)\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), API_REQUEST_TIMEOUT_MS);\n\n // Prefer Bearer token auth when the \"password\" looks like a GitHub token,\n // but fall back to Basic auth for traditional username/password credentials.\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github+json',\n 'User-Agent': 'tuck-dotfiles-manager',\n };\n\n const looksLikeToken =\n typeof password === 'string' &&\n password.length >= MIN_GITHUB_TOKEN_LENGTH &&\n GITHUB_TOKEN_PREFIXES.some((prefix) => password.startsWith(prefix));\n\n if (looksLikeToken) {\n headers.Authorization = `Bearer ${password}`;\n } else {\n const auth = Buffer.from(`${username}:${password}`).toString('base64');\n headers.Authorization = `Basic ${auth}`;\n }\n\n try {\n const response = await fetch('https://api.github.com/user', {\n method: 'GET',\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // 200 OK means credentials are valid\n if (response.status === 200) {\n try {\n // Parse user data to extract username (in case it differs from metadata)\n const userData = (await response.json()) as { login?: string };\n const apiUsername = userData.login || username;\n return { valid: true, username: apiUsername };\n } catch {\n // Even if we can't parse, 200 OK means auth succeeded\n // Use username from credentials if valid, otherwise fall back to metadata username\n const effectiveUsername = (username && username.trim()) || metadata.username;\n return { valid: true, username: effectiveUsername };\n }\n }\n\n // 401 Unauthorized means invalid credentials\n if (response.status === 401) {\n // Check if token might be expired based on creation date\n if (metadata.createdAt) {\n const daysSinceCreation = Math.floor(\n (Date.now() - metadata.createdAt.getTime()) / (1000 * 60 * 60 * 24)\n );\n\n // Fine-grained tokens often expire in 90 days, classic can vary\n if (daysSinceCreation > TOKEN_EXPIRATION_WARNING_DAYS) {\n return { valid: false, reason: 'expired', username: metadata.username };\n }\n }\n return { valid: false, reason: 'invalid', username: metadata.username };\n }\n\n // 403 Forbidden could mean token is invalid or lacks permissions\n if (response.status === 403) {\n return { valid: false, reason: 'invalid', username: metadata.username };\n }\n\n // Other status codes are unexpected\n return { valid: false, reason: 'unknown', username: metadata.username };\n } catch (fetchError) {\n clearTimeout(timeoutId);\n throw fetchError;\n }\n } catch (error) {\n const errorStr = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n\n // Check for timeout/abort errors\n if (errorStr.includes('aborted') || errorStr.includes('timeout')) {\n return { valid: false, reason: 'network', username: metadata.username };\n }\n\n // Check for network-related errors\n if (\n errorStr.includes('network') ||\n errorStr.includes('enotfound') ||\n errorStr.includes('econnrefused') ||\n errorStr.includes('could not resolve') ||\n errorStr.includes('fetch failed') ||\n errorStr.includes('getaddrinfo')\n ) {\n return { valid: false, reason: 'network', username: metadata.username };\n }\n\n return { valid: false, reason: 'unknown', username: metadata.username };\n }\n};\n\n/**\n * Diagnose authentication issues and provide helpful suggestions\n */\nexport const diagnoseAuthIssue = async (): Promise<{\n issue: string;\n suggestions: string[];\n}> => {\n const metadata = await getStoredCredentialMetadata();\n\n if (!metadata?.hasToken) {\n return {\n issue: 'No GitHub credentials configured',\n suggestions: [\n 'Set up authentication using one of the methods below',\n 'Run `tuck init` to configure GitHub access',\n ],\n };\n }\n\n const testResult = await testStoredCredentials();\n\n if (testResult.valid) {\n return {\n issue: 'Credentials appear to be working',\n suggestions: ['Try the operation again'],\n };\n }\n\n switch (testResult.reason) {\n case 'expired':\n return {\n issue: `Your ${metadata.type || 'GitHub'} token has likely expired`,\n suggestions: [\n metadata.type === 'fine-grained'\n ? 'Create a new fine-grained token at: https://github.com/settings/tokens?type=beta'\n : 'Create a new token at: https://github.com/settings/tokens/new',\n 'Use the same permissions as before',\n 'Run `tuck init` to update your credentials',\n ],\n };\n\n case 'invalid':\n return {\n issue: 'Your GitHub credentials are invalid',\n suggestions: [\n 'The token may have been revoked or is incorrect',\n 'Check your tokens at: https://github.com/settings/tokens',\n 'Create a new token and run `tuck init` to update',\n ],\n };\n\n case 'network':\n return {\n issue: 'Could not connect to GitHub',\n suggestions: [\n 'Check your internet connection',\n 'GitHub may be experiencing issues - check https://githubstatus.com',\n 'Try again in a moment',\n ],\n };\n\n default:\n return {\n issue: 'Unknown authentication issue',\n suggestions: [\n 'Try creating a new token',\n 'Check https://github.com/settings/tokens for your existing tokens',\n 'Run `tuck init` to reconfigure authentication',\n ],\n };\n }\n};\n\n/**\n * Update stored credentials with a new token\n */\nexport const updateStoredCredentials = async (\n token: string,\n type?: 'fine-grained' | 'classic'\n): Promise<void> => {\n const metadata = await getStoredCredentialMetadata();\n const username = metadata?.username;\n\n if (!username) {\n throw new Error(\n 'GitHub credential metadata is incomplete or corrupted (missing username). ' +\n 'Please remove the credential file and re-authenticate by running `tuck config` or `tuck init`.'\n );\n }\n\n // Determine token type, preferring explicit type, then stored metadata, then detection\n const detectedType = detectTokenType(token);\n const tokenType = type ?? metadata?.type ?? detectedType;\n\n // Ensure we have a valid token type (not 'unknown')\n if (tokenType !== 'fine-grained' && tokenType !== 'classic') {\n throw new Error(\n 'Could not determine GitHub token type. The token format is not recognized. ' +\n 'Please verify your token starts with \"github_pat_\" (fine-grained) or \"ghp_\" (classic), ' +\n 'or generate a new token at https://github.com/settings/tokens'\n );\n }\n\n // Remove old credentials first\n await removeStoredCredentials();\n\n // Store new credentials\n await storeGitHubCredentials(username, token, tokenType);\n};\n\n/**\n * Detect token type from the token format\n */\nexport const detectTokenType = (token: string): 'fine-grained' | 'classic' | 'unknown' => {\n // Fine-grained tokens start with github_pat_\n if (token.startsWith('github_pat_')) {\n return 'fine-grained';\n }\n // Classic tokens start with ghp_\n if (token.startsWith('ghp_')) {\n return 'classic';\n }\n return 'unknown';\n};\n","import { join, basename, isAbsolute } from 'path';\nimport { readdir, stat } from 'fs/promises';\nimport { platform } from 'os';\nimport { pathExists, expandPath, collapsePath } from './paths.js';\n\nconst IS_MACOS = platform() === 'darwin';\nconst IS_LINUX = platform() === 'linux';\n\nexport interface DetectedFile {\n path: string;\n name: string;\n category: string;\n description: string;\n isDirectory: boolean;\n size?: number;\n sensitive?: boolean;\n exclude?: string[]; // Patterns to exclude within directories\n}\n\nexport interface DetectionCategory {\n name: string;\n icon: string;\n description: string;\n}\n\nexport const DETECTION_CATEGORIES: Record<string, DetectionCategory> = {\n shell: {\n name: 'Shell',\n icon: '$',\n description: 'Shell configs, aliases, functions, and environment',\n },\n git: {\n name: 'Git',\n icon: '*',\n description: 'Git settings, aliases, and global ignores',\n },\n editors: {\n name: 'Editors',\n icon: '>',\n description: 'Editor configurations and settings',\n },\n terminal: {\n name: 'Terminal',\n icon: '#',\n description: 'Terminal emulators and tmux/screen',\n },\n prompt: {\n name: 'Prompt & Theme',\n icon: '~',\n description: 'Shell prompts, themes, and color schemes',\n },\n cli: {\n name: 'CLI Tools',\n icon: '%',\n description: 'Command-line tool configurations',\n },\n languages: {\n name: 'Languages',\n icon: '@',\n description: 'Programming language and package manager configs',\n },\n ssh: {\n name: 'SSH & Security',\n icon: '!',\n description: 'SSH config and GPG settings (no private keys)',\n },\n xdg: {\n name: 'XDG Apps',\n icon: '.',\n description: 'Applications using ~/.config standard',\n },\n desktop: {\n name: 'Desktop & WM',\n icon: '+',\n description: 'Window managers and desktop environment configs',\n },\n scripts: {\n name: 'Scripts',\n icon: '/',\n description: 'Custom scripts and local binaries',\n },\n macos: {\n name: 'macOS',\n icon: '^',\n description: 'macOS-specific configurations',\n },\n misc: {\n name: 'Other',\n icon: '-',\n description: 'Other configuration files',\n },\n};\n\n/**\n * Comprehensive list of dotfiles to detect\n */\nconst DOTFILE_PATTERNS: Array<{\n path: string;\n category: string;\n description: string;\n sensitive?: boolean;\n exclude?: string[];\n platform?: 'darwin' | 'linux' | 'all';\n}> = [\n // ==================== SHELL CONFIGURATION ====================\n // Bash\n { path: '~/.bashrc', category: 'shell', description: 'Bash interactive shell config' },\n { path: '~/.bash_profile', category: 'shell', description: 'Bash login shell config' },\n { path: '~/.bash_aliases', category: 'shell', description: 'Bash aliases' },\n { path: '~/.bash_functions', category: 'shell', description: 'Bash functions' },\n { path: '~/.bash_logout', category: 'shell', description: 'Bash logout script' },\n\n // Zsh\n { path: '~/.zshrc', category: 'shell', description: 'Zsh interactive shell config' },\n { path: '~/.zprofile', category: 'shell', description: 'Zsh login shell config' },\n { path: '~/.zshenv', category: 'shell', description: 'Zsh environment variables' },\n { path: '~/.zlogin', category: 'shell', description: 'Zsh login script' },\n { path: '~/.zlogout', category: 'shell', description: 'Zsh logout script' },\n { path: '~/.zsh', category: 'shell', description: 'Zsh configuration directory' },\n\n // Fish\n { path: '~/.config/fish/config.fish', category: 'shell', description: 'Fish shell config' },\n { path: '~/.config/fish/functions', category: 'shell', description: 'Fish functions' },\n { path: '~/.config/fish/completions', category: 'shell', description: 'Fish completions' },\n { path: '~/.config/fish/conf.d', category: 'shell', description: 'Fish config snippets' },\n\n // Generic shell\n { path: '~/.profile', category: 'shell', description: 'Generic shell profile' },\n { path: '~/.aliases', category: 'shell', description: 'Shell aliases' },\n { path: '~/.functions', category: 'shell', description: 'Shell functions' },\n { path: '~/.exports', category: 'shell', description: 'Environment exports' },\n { path: '~/.inputrc', category: 'shell', description: 'Readline configuration' },\n { path: '~/.hushlogin', category: 'shell', description: 'Suppress login message' },\n\n // ==================== GIT CONFIGURATION ====================\n { path: '~/.gitconfig', category: 'git', description: 'Git global configuration' },\n { path: '~/.gitignore_global', category: 'git', description: 'Global gitignore patterns' },\n { path: '~/.gitignore', category: 'git', description: 'Global gitignore (alt location)' },\n { path: '~/.gitmessage', category: 'git', description: 'Git commit message template' },\n { path: '~/.gitattributes', category: 'git', description: 'Git attributes' },\n { path: '~/.config/git/config', category: 'git', description: 'Git XDG config' },\n { path: '~/.config/git/ignore', category: 'git', description: 'Git XDG ignore' },\n { path: '~/.config/gh', category: 'git', description: 'GitHub CLI config' },\n { path: '~/.config/hub', category: 'git', description: 'Hub CLI config' },\n\n // ==================== EDITORS & IDES ====================\n // Vim/Neovim\n { path: '~/.vimrc', category: 'editors', description: 'Vim configuration' },\n { path: '~/.vim', category: 'editors', description: 'Vim directory', exclude: ['plugged', 'bundle', '.netrwhist'] },\n { path: '~/.config/nvim', category: 'editors', description: 'Neovim configuration' },\n { path: '~/.ideavimrc', category: 'editors', description: 'IdeaVim (JetBrains) config' },\n\n // Emacs\n { path: '~/.emacs', category: 'editors', description: 'Emacs configuration' },\n { path: '~/.emacs.d/init.el', category: 'editors', description: 'Emacs init file' },\n { path: '~/.doom.d', category: 'editors', description: 'Doom Emacs config' },\n { path: '~/.spacemacs', category: 'editors', description: 'Spacemacs config' },\n\n // VS Code\n { path: '~/.config/Code/User/settings.json', category: 'editors', description: 'VS Code settings', platform: 'linux' },\n { path: '~/.config/Code/User/keybindings.json', category: 'editors', description: 'VS Code keybindings', platform: 'linux' },\n { path: '~/.config/Code/User/snippets', category: 'editors', description: 'VS Code snippets', platform: 'linux' },\n { path: '~/Library/Application Support/Code/User/settings.json', category: 'editors', description: 'VS Code settings', platform: 'darwin' },\n { path: '~/Library/Application Support/Code/User/keybindings.json', category: 'editors', description: 'VS Code keybindings', platform: 'darwin' },\n { path: '~/Library/Application Support/Code/User/snippets', category: 'editors', description: 'VS Code snippets', platform: 'darwin' },\n\n // Cursor (VS Code fork)\n { path: '~/.config/Cursor/User/settings.json', category: 'editors', description: 'Cursor settings', platform: 'linux' },\n { path: '~/Library/Application Support/Cursor/User/settings.json', category: 'editors', description: 'Cursor settings', platform: 'darwin' },\n\n // Other editors\n { path: '~/.nanorc', category: 'editors', description: 'Nano configuration' },\n { path: '~/.config/micro', category: 'editors', description: 'Micro editor config' },\n { path: '~/.config/helix', category: 'editors', description: 'Helix editor config' },\n { path: '~/.sublime-text/Packages/User', category: 'editors', description: 'Sublime Text settings' },\n\n // ==================== TERMINAL & MULTIPLEXERS ====================\n // Tmux\n { path: '~/.tmux.conf', category: 'terminal', description: 'Tmux configuration' },\n { path: '~/.tmux', category: 'terminal', description: 'Tmux directory' },\n { path: '~/.config/tmux/tmux.conf', category: 'terminal', description: 'Tmux XDG config' },\n\n // Screen\n { path: '~/.screenrc', category: 'terminal', description: 'GNU Screen configuration' },\n\n // Terminal emulators\n { path: '~/.config/alacritty', category: 'terminal', description: 'Alacritty terminal config' },\n { path: '~/.config/kitty', category: 'terminal', description: 'Kitty terminal config' },\n { path: '~/.config/wezterm', category: 'terminal', description: 'WezTerm config' },\n { path: '~/.wezterm.lua', category: 'terminal', description: 'WezTerm config (alt)' },\n { path: '~/.config/hyper', category: 'terminal', description: 'Hyper terminal config' },\n { path: '~/.hyper.js', category: 'terminal', description: 'Hyper terminal config (alt)' },\n { path: '~/.config/foot', category: 'terminal', description: 'Foot terminal config' },\n { path: '~/.config/terminator', category: 'terminal', description: 'Terminator config' },\n { path: '~/.config/tilix', category: 'terminal', description: 'Tilix terminal config' },\n { path: '~/Library/Preferences/com.googlecode.iterm2.plist', category: 'terminal', description: 'iTerm2 preferences', platform: 'darwin' },\n\n // ==================== PROMPT & THEMES ====================\n { path: '~/.config/starship.toml', category: 'prompt', description: 'Starship prompt config' },\n { path: '~/.p10k.zsh', category: 'prompt', description: 'Powerlevel10k config' },\n { path: '~/.oh-my-zsh/custom', category: 'prompt', description: 'Oh My Zsh customizations' },\n { path: '~/.config/powerline', category: 'prompt', description: 'Powerline config' },\n { path: '~/.dir_colors', category: 'prompt', description: 'Directory colors' },\n { path: '~/.dircolors', category: 'prompt', description: 'Directory colors (alt)' },\n\n // ==================== CLI TOOLS ====================\n // Search & navigation\n { path: '~/.config/ripgrep', category: 'cli', description: 'Ripgrep config' },\n { path: '~/.ripgreprc', category: 'cli', description: 'Ripgrep config (alt)' },\n { path: '~/.rgrc', category: 'cli', description: 'Ripgrep config (short)' },\n { path: '~/.config/fd', category: 'cli', description: 'fd find config' },\n { path: '~/.fdignore', category: 'cli', description: 'fd ignore patterns' },\n { path: '~/.config/bat', category: 'cli', description: 'bat (better cat) config' },\n { path: '~/.config/lsd', category: 'cli', description: 'lsd (better ls) config' },\n { path: '~/.config/exa', category: 'cli', description: 'exa config' },\n { path: '~/.config/eza', category: 'cli', description: 'eza config' },\n\n // Fuzzy finders\n { path: '~/.fzf.zsh', category: 'cli', description: 'fzf Zsh integration' },\n { path: '~/.fzf.bash', category: 'cli', description: 'fzf Bash integration' },\n { path: '~/.config/fzf', category: 'cli', description: 'fzf config directory' },\n\n // Network tools\n { path: '~/.curlrc', category: 'cli', description: 'curl configuration' },\n { path: '~/.wgetrc', category: 'cli', description: 'wget configuration' },\n { path: '~/.netrc', category: 'cli', description: 'Network credentials', sensitive: true },\n { path: '~/.config/aria2', category: 'cli', description: 'aria2 download manager' },\n\n // System monitoring\n { path: '~/.config/htop', category: 'cli', description: 'htop config' },\n { path: '~/.config/btop', category: 'cli', description: 'btop config' },\n { path: '~/.config/bottom', category: 'cli', description: 'bottom config' },\n { path: '~/.config/glances', category: 'cli', description: 'Glances config' },\n\n // Other CLI tools\n { path: '~/.config/lazygit', category: 'cli', description: 'Lazygit config' },\n { path: '~/.config/lazydocker', category: 'cli', description: 'Lazydocker config' },\n { path: '~/.config/ranger', category: 'cli', description: 'Ranger file manager' },\n { path: '~/.config/lf', category: 'cli', description: 'lf file manager' },\n { path: '~/.config/yazi', category: 'cli', description: 'Yazi file manager' },\n { path: '~/.config/nnn', category: 'cli', description: 'nnn file manager' },\n { path: '~/.config/zoxide', category: 'cli', description: 'zoxide (smart cd)' },\n { path: '~/.config/atuin', category: 'cli', description: 'Atuin shell history' },\n { path: '~/.config/thefuck', category: 'cli', description: 'thefuck config' },\n { path: '~/.config/direnv', category: 'cli', description: 'direnv config' },\n { path: '~/.direnvrc', category: 'cli', description: 'direnv config (alt)' },\n { path: '~/.ackrc', category: 'cli', description: 'ack search config' },\n { path: '~/.agignore', category: 'cli', description: 'silver searcher ignore' },\n { path: '~/.editorconfig', category: 'cli', description: 'EditorConfig' },\n\n // ==================== LANGUAGES & PACKAGE MANAGERS ====================\n // Node.js\n { path: '~/.npmrc', category: 'languages', description: 'npm configuration' },\n { path: '~/.yarnrc', category: 'languages', description: 'Yarn configuration' },\n { path: '~/.config/yarn', category: 'languages', description: 'Yarn config directory' },\n { path: '~/.bunfig.toml', category: 'languages', description: 'Bun configuration' },\n { path: '~/.nvmrc', category: 'languages', description: 'nvm default version' },\n { path: '~/.node-version', category: 'languages', description: 'Node version file' },\n\n // Python\n { path: '~/.config/pip', category: 'languages', description: 'pip configuration' },\n { path: '~/.pip', category: 'languages', description: 'pip config (legacy)' },\n { path: '~/.pypirc', category: 'languages', description: 'PyPI configuration', sensitive: true },\n { path: '~/.python-version', category: 'languages', description: 'pyenv version' },\n { path: '~/.config/flake8', category: 'languages', description: 'Flake8 config' },\n { path: '~/.config/black', category: 'languages', description: 'Black formatter' },\n { path: '~/.config/ruff', category: 'languages', description: 'Ruff linter' },\n { path: '~/.pylintrc', category: 'languages', description: 'Pylint config' },\n { path: '~/.config/pypoetry', category: 'languages', description: 'Poetry config' },\n { path: '~/.config/pdm', category: 'languages', description: 'PDM config' },\n\n // Ruby\n { path: '~/.gemrc', category: 'languages', description: 'RubyGems configuration' },\n { path: '~/.irbrc', category: 'languages', description: 'IRB configuration' },\n { path: '~/.pryrc', category: 'languages', description: 'Pry configuration' },\n { path: '~/.ruby-version', category: 'languages', description: 'Ruby version file' },\n { path: '~/.bundle/config', category: 'languages', description: 'Bundler config' },\n\n // Rust\n { path: '~/.cargo/config.toml', category: 'languages', description: 'Cargo configuration' },\n { path: '~/.cargo/config', category: 'languages', description: 'Cargo config (legacy)' },\n { path: '~/.rustfmt.toml', category: 'languages', description: 'rustfmt config' },\n\n // Go\n { path: '~/.config/go', category: 'languages', description: 'Go configuration' },\n\n // Java/JVM\n { path: '~/.gradle/gradle.properties', category: 'languages', description: 'Gradle properties' },\n { path: '~/.m2/settings.xml', category: 'languages', description: 'Maven settings' },\n { path: '~/.sbt', category: 'languages', description: 'SBT config' },\n\n // Docker\n { path: '~/.docker/config.json', category: 'languages', description: 'Docker config' },\n\n // Kubernetes\n { path: '~/.kube/config', category: 'languages', description: 'kubectl config', sensitive: true },\n\n // Cloud\n { path: '~/.aws/config', category: 'languages', description: 'AWS CLI config' },\n { path: '~/.config/gcloud', category: 'languages', description: 'Google Cloud config' },\n\n // ==================== SSH & SECURITY ====================\n {\n path: '~/.ssh/config',\n category: 'ssh',\n description: 'SSH client configuration',\n sensitive: true,\n },\n {\n path: '~/.ssh/known_hosts',\n category: 'ssh',\n description: 'SSH known hosts',\n },\n {\n path: '~/.ssh/authorized_keys',\n category: 'ssh',\n description: 'Authorized SSH keys',\n },\n {\n path: '~/.ssh/rc',\n category: 'ssh',\n description: 'SSH connection script',\n },\n {\n path: '~/.gnupg/gpg.conf',\n category: 'ssh',\n description: 'GPG configuration',\n sensitive: true,\n },\n {\n path: '~/.gnupg/gpg-agent.conf',\n category: 'ssh',\n description: 'GPG agent configuration',\n },\n\n // ==================== XDG CONFIG APPS ====================\n { path: '~/.config/fontconfig', category: 'xdg', description: 'Font configuration' },\n { path: '~/.config/gtk-3.0', category: 'xdg', description: 'GTK3 settings' },\n { path: '~/.config/gtk-4.0', category: 'xdg', description: 'GTK4 settings' },\n { path: '~/.config/qt5ct', category: 'xdg', description: 'Qt5 settings' },\n { path: '~/.config/mimeapps.list', category: 'xdg', description: 'Default applications' },\n { path: '~/.config/user-dirs.dirs', category: 'xdg', description: 'XDG user directories' },\n { path: '~/.config/autostart', category: 'xdg', description: 'Autostart applications' },\n { path: '~/.config/environment.d', category: 'xdg', description: 'Environment variables' },\n { path: '~/.config/systemd/user', category: 'xdg', description: 'User systemd services', platform: 'linux' },\n { path: '~/.config/dunst', category: 'xdg', description: 'Dunst notifications', platform: 'linux' },\n { path: '~/.config/rofi', category: 'xdg', description: 'Rofi launcher', platform: 'linux' },\n { path: '~/.config/wofi', category: 'xdg', description: 'Wofi launcher', platform: 'linux' },\n\n // ==================== DESKTOP & WINDOW MANAGERS ====================\n // i3/sway\n { path: '~/.config/i3', category: 'desktop', description: 'i3 window manager', platform: 'linux' },\n { path: '~/.config/sway', category: 'desktop', description: 'Sway (Wayland i3)', platform: 'linux' },\n { path: '~/.config/i3status', category: 'desktop', description: 'i3status bar', platform: 'linux' },\n { path: '~/.config/i3status-rust', category: 'desktop', description: 'i3status-rust bar', platform: 'linux' },\n { path: '~/.config/waybar', category: 'desktop', description: 'Waybar', platform: 'linux' },\n { path: '~/.config/polybar', category: 'desktop', description: 'Polybar', platform: 'linux' },\n\n // Hyprland\n { path: '~/.config/hypr', category: 'desktop', description: 'Hyprland config', platform: 'linux' },\n\n // Other WMs\n { path: '~/.config/bspwm', category: 'desktop', description: 'bspwm config', platform: 'linux' },\n { path: '~/.config/sxhkd', category: 'desktop', description: 'sxhkd hotkeys', platform: 'linux' },\n { path: '~/.config/awesome', category: 'desktop', description: 'AwesomeWM config', platform: 'linux' },\n { path: '~/.config/openbox', category: 'desktop', description: 'Openbox config', platform: 'linux' },\n { path: '~/.config/qtile', category: 'desktop', description: 'Qtile config', platform: 'linux' },\n { path: '~/.config/herbstluftwm', category: 'desktop', description: 'herbstluftwm config', platform: 'linux' },\n\n // macOS window managers\n { path: '~/.yabairc', category: 'desktop', description: 'yabai config', platform: 'darwin' },\n { path: '~/.config/yabai', category: 'desktop', description: 'yabai config (XDG)', platform: 'darwin' },\n { path: '~/.skhdrc', category: 'desktop', description: 'skhd hotkeys', platform: 'darwin' },\n { path: '~/.config/skhd', category: 'desktop', description: 'skhd config (XDG)', platform: 'darwin' },\n { path: '~/.config/spacebar', category: 'desktop', description: 'spacebar config', platform: 'darwin' },\n { path: '~/.config/borders', category: 'desktop', description: 'borders config', platform: 'darwin' },\n { path: '~/.aerospace.toml', category: 'desktop', description: 'AeroSpace config', platform: 'darwin' },\n\n // Picom/Compton\n { path: '~/.config/picom', category: 'desktop', description: 'Picom compositor', platform: 'linux' },\n { path: '~/.config/picom.conf', category: 'desktop', description: 'Picom config (alt)', platform: 'linux' },\n\n // ==================== SCRIPTS & BINS ====================\n { path: '~/.local/bin', category: 'scripts', description: 'Local scripts and binaries' },\n { path: '~/bin', category: 'scripts', description: 'User bin directory' },\n { path: '~/.scripts', category: 'scripts', description: 'Custom scripts' },\n\n // ==================== MACOS SPECIFIC ====================\n { path: '~/.finicky.js', category: 'macos', description: 'Finicky browser picker', platform: 'darwin' },\n { path: '~/.config/karabiner', category: 'macos', description: 'Karabiner key remapping', platform: 'darwin' },\n { path: '~/.hammerspoon', category: 'macos', description: 'Hammerspoon automation', platform: 'darwin' },\n { path: '~/.config/raycast', category: 'macos', description: 'Raycast config', platform: 'darwin' },\n\n // ==================== MISCELLANEOUS ====================\n { path: '~/.config/neofetch', category: 'misc', description: 'Neofetch config' },\n { path: '~/.config/fastfetch', category: 'misc', description: 'Fastfetch config' },\n { path: '~/.config/onefetch', category: 'misc', description: 'Onefetch config' },\n { path: '~/.config/topgrade.toml', category: 'misc', description: 'Topgrade updater' },\n { path: '~/.config/youtube-dl', category: 'misc', description: 'youtube-dl config' },\n { path: '~/.config/yt-dlp', category: 'misc', description: 'yt-dlp config' },\n { path: '~/.config/mpv', category: 'misc', description: 'MPV media player' },\n { path: '~/.config/newsboat', category: 'misc', description: 'Newsboat RSS reader' },\n { path: '~/.config/cmus', category: 'misc', description: 'cmus music player' },\n { path: '~/.config/spotify-tui', category: 'misc', description: 'Spotify TUI' },\n { path: '~/.mailcap', category: 'misc', description: 'MIME type handlers' },\n { path: '~/.muttrc', category: 'misc', description: 'Mutt email client' },\n { path: '~/.config/mutt', category: 'misc', description: 'Mutt config directory' },\n { path: '~/.config/neomutt', category: 'misc', description: 'Neomutt config' },\n { path: '~/.Xresources', category: 'misc', description: 'X11 resources', platform: 'linux' },\n { path: '~/.Xmodmap', category: 'misc', description: 'X11 keymap', platform: 'linux' },\n { path: '~/.xinitrc', category: 'misc', description: 'X11 init script', platform: 'linux' },\n { path: '~/.xprofile', category: 'misc', description: 'X11 profile', platform: 'linux' },\n];\n\n/**\n * Patterns to exclude from detection\n * These are files/directories that should NEVER be tracked as they contain\n * ephemeral data, caches, or large binary files\n */\nexport const DEFAULT_EXCLUSION_PATTERNS = {\n // Cache directories - contain downloaded packages, build artifacts, etc.\n cacheDirectories: [\n '~/.cache',\n '~/.npm',\n '~/.yarn/cache',\n '~/.pnpm-store',\n '~/.bun/install/cache',\n '~/.cargo/registry',\n '~/.cargo/git',\n '~/.rustup/toolchains',\n '~/.go/pkg',\n '~/.m2/repository',\n '~/.gradle/caches',\n '~/.gradle/wrapper',\n '~/.ivy2/cache',\n '~/.sbt/boot',\n '~/.coursier/cache',\n '~/.pip/cache',\n '~/.local/pipx/venvs',\n '~/.pyenv/versions',\n '~/.rbenv/versions',\n '~/.nvm/versions',\n '~/.sdkman/candidates',\n '~/.local/share/virtualenvs',\n '~/.conda/pkgs',\n '~/.docker/buildx',\n '~/.docker/volumes',\n '~/.vagrant.d/boxes',\n '~/.terraform.d/plugins',\n '~/.composer/cache',\n '~/.cpan/build',\n '~/.cpanm/work',\n '~/.gem/ruby',\n '~/.thumbnails',\n '~/.local/share/Trash',\n '~/Library/Caches',\n '~/.node_modules',\n '~/.electron',\n ],\n\n // History and log files - contain ephemeral session data\n historyFiles: [\n '~/.bash_history',\n '~/.zsh_history',\n '~/.zhistory',\n '~/.sh_history',\n '~/.fish_history',\n '~/.config/fish/fish_history',\n '~/.lesshst',\n '~/.node_repl_history',\n '~/.python_history',\n '~/.irb_history',\n '~/.pry_history',\n '~/.mysql_history',\n '~/.psql_history',\n '~/.sqlite_history',\n '~/.rediscli_history',\n '~/.mongosh_history',\n '~/.dbshell',\n '~/.wget-hsts',\n '~/.recently-used',\n '~/.local/share/recently-used.xbel',\n '~/.viminfo',\n '~/.vim_mru_files',\n '~/.netrwhist',\n ],\n\n // Binary file extensions - images, fonts, compiled output\n binaryPatterns: [\n /\\.(png|jpg|jpeg|gif|ico|svg|webp|bmp|tiff?)$/i,\n /\\.(woff2?|ttf|otf|eot)$/i,\n /\\.(so|dylib|dll|exe|bin|app)$/i,\n /\\.(o|a|lib|obj|pyc|pyo|class)$/i,\n /\\.(db|sqlite|sqlite3|leveldb)$/i,\n /\\.(zip|tar|gz|bz2|xz|7z|rar)$/i,\n /\\.(pdf|doc|docx|xls|xlsx|ppt|pptx)$/i,\n /\\.(mp3|mp4|wav|flac|avi|mkv|mov)$/i,\n ],\n\n // Temporary and lock files\n tempFiles: [\n /\\.lock$/i,\n /\\.lockfile$/i,\n /\\.tmp$/i,\n /\\.temp$/i,\n /\\.swp$/i,\n /\\.swo$/i,\n /~$/,\n /\\.bak$/i,\n /\\.backup$/i,\n /\\.orig$/i,\n ],\n};\n\n/**\n * Check if a path should be excluded from detection/tracking\n */\nexport const shouldExcludeFile = (path: string): boolean => {\n // Normalize path to use ~ prefix\n // Handle both tilde paths and absolute paths that point to home directory\n let normalizedPath: string;\n if (path.startsWith('~/')) {\n // Already in tilde notation\n normalizedPath = path;\n } else if (path.startsWith(expandPath('~/'))) {\n // Absolute path within home directory - convert to tilde notation\n normalizedPath = path.replace(expandPath('~/'), '~/');\n } else if (isAbsolute(path)) {\n // Other absolute path - try to collapse to tilde notation\n normalizedPath = collapsePath(path);\n } else {\n // Relative path, keep as-is\n normalizedPath = path;\n }\n\n // Check cache directories (directory-aware prefix match)\n // Must match exactly or be a subdirectory (with /)\n for (const cacheDir of DEFAULT_EXCLUSION_PATTERNS.cacheDirectories) {\n if (\n normalizedPath === cacheDir ||\n normalizedPath.startsWith(cacheDir + '/')\n ) {\n return true;\n }\n }\n\n // Check history files (exact match)\n if (DEFAULT_EXCLUSION_PATTERNS.historyFiles.includes(normalizedPath)) {\n return true;\n }\n\n // Check binary patterns (regex on filename)\n const filename = basename(normalizedPath);\n for (const pattern of DEFAULT_EXCLUSION_PATTERNS.binaryPatterns) {\n if (pattern.test(filename)) {\n return true;\n }\n }\n\n // Check temp file patterns (regex on filename)\n for (const pattern of DEFAULT_EXCLUSION_PATTERNS.tempFiles) {\n if (pattern.test(filename)) {\n return true;\n }\n }\n\n return false;\n};\n\n/**\n * Check if a path should be included for current platform\n */\nconst shouldIncludeForPlatform = (item: { platform?: string }): boolean => {\n if (!item.platform || item.platform === 'all') return true;\n if (item.platform === 'darwin' && IS_MACOS) return true;\n if (item.platform === 'linux' && IS_LINUX) return true;\n return false;\n};\n\n/**\n * Get file/directory size\n */\nconst getSize = async (path: string): Promise<number | undefined> => {\n try {\n const stats = await stat(path);\n return stats.size;\n } catch {\n return undefined;\n }\n};\n\n/**\n * Check if path is a directory\n */\nconst isDirectory = async (path: string): Promise<boolean> => {\n try {\n const stats = await stat(path);\n return stats.isDirectory();\n } catch {\n return false;\n }\n};\n\n/**\n * Scan system for existing dotfiles\n * @param options - Optional configuration for detection\n * @param options.includeExcluded - If true, include files that match exclusion patterns (default: false). Set to true when you need to detect all dotfiles regardless of exclusion rules, such as for manual review or special operations.\n */\nexport const detectDotfiles = async (options?: {\n includeExcluded?: boolean;\n}): Promise<DetectedFile[]> => {\n const detected: DetectedFile[] = [];\n const includeExcluded = options?.includeExcluded ?? false;\n\n for (const pattern of DOTFILE_PATTERNS) {\n // Skip if not for current platform\n if (!shouldIncludeForPlatform(pattern)) continue;\n\n // Skip if matches exclusion patterns (unless explicitly including)\n if (!includeExcluded && shouldExcludeFile(pattern.path)) continue;\n\n const fullPath = expandPath(pattern.path);\n\n if (await pathExists(fullPath)) {\n const isDir = await isDirectory(fullPath);\n const size = await getSize(fullPath);\n\n detected.push({\n path: pattern.path,\n name: basename(pattern.path),\n category: pattern.category,\n description: pattern.description,\n isDirectory: isDir,\n size,\n sensitive: pattern.sensitive,\n exclude: pattern.exclude,\n });\n }\n }\n\n return detected;\n};\n\n/**\n * Group detected files by category\n */\nexport const groupByCategory = (\n files: DetectedFile[]\n): Record<string, DetectedFile[]> => {\n const grouped: Record<string, DetectedFile[]> = {};\n\n for (const file of files) {\n if (!grouped[file.category]) {\n grouped[file.category] = [];\n }\n grouped[file.category].push(file);\n }\n\n return grouped;\n};\n\n/**\n * Get SSH files that are safe to backup (no private keys)\n */\nexport const getSafeSSHFiles = async (): Promise<string[]> => {\n const sshDir = expandPath('~/.ssh');\n const safeFiles: string[] = [];\n\n if (!(await pathExists(sshDir))) {\n return safeFiles;\n }\n\n try {\n const entries = await readdir(sshDir);\n\n for (const entry of entries) {\n // Skip private keys and other sensitive files\n if (\n entry.endsWith('.pub') ||\n entry === 'config' ||\n entry === 'known_hosts' ||\n entry === 'authorized_keys' ||\n entry === 'rc' ||\n entry === 'environment'\n ) {\n safeFiles.push(join('~/.ssh', entry));\n }\n }\n } catch {\n // Ignore errors\n }\n\n return safeFiles;\n};\n\n/**\n * Format file size for display\n */\nexport const formatSize = (bytes: number | undefined): string => {\n if (bytes === undefined) return '';\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;\n};\n\n/**\n * Get count of files in each category\n */\nexport const getCategoryCounts = (\n files: DetectedFile[]\n): Record<string, number> => {\n const counts: Record<string, number> = {};\n\n for (const file of files) {\n counts[file.category] = (counts[file.category] || 0) + 1;\n }\n\n return counts;\n};\n","import { createHash } from 'crypto';\nimport { readFile, stat, lstat, readdir, copyFile, symlink, unlink, rm } from 'fs/promises';\nimport { copy, ensureDir } from 'fs-extra';\nimport { join, dirname, basename } from 'path';\nimport { constants } from 'fs';\nimport { FileNotFoundError, PermissionError } from '../errors.js';\nimport { expandPath, pathExists, isDirectory } from './paths.js';\n\nexport interface FileInfo {\n path: string;\n isDirectory: boolean;\n isSymlink: boolean;\n size: number;\n permissions: string;\n modified: Date;\n}\n\nexport interface CopyResult {\n source: string;\n destination: string;\n fileCount: number;\n totalSize: number;\n}\n\nexport const getFileChecksum = async (filepath: string): Promise<string> => {\n const expandedPath = expandPath(filepath);\n\n if (await isDirectory(expandedPath)) {\n // For directories, create a hash of all file checksums\n const files = await getDirectoryFiles(expandedPath);\n const hashes: string[] = [];\n\n for (const file of files) {\n const content = await readFile(file);\n hashes.push(createHash('sha256').update(content).digest('hex'));\n }\n\n return createHash('sha256').update(hashes.join('')).digest('hex');\n }\n\n const content = await readFile(expandedPath);\n return createHash('sha256').update(content).digest('hex');\n};\n\nexport const getFileInfo = async (filepath: string): Promise<FileInfo> => {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n throw new FileNotFoundError(filepath);\n }\n\n try {\n const stats = await stat(expandedPath);\n const permissions = (stats.mode & 0o777).toString(8).padStart(3, '0');\n\n return {\n path: expandedPath,\n isDirectory: stats.isDirectory(),\n isSymlink: stats.isSymbolicLink(),\n size: stats.size,\n permissions,\n modified: stats.mtime,\n };\n } catch (error) {\n throw new PermissionError(filepath, 'read');\n }\n};\n\nexport const getDirectoryFiles = async (dirpath: string): Promise<string[]> => {\n const expandedPath = expandPath(dirpath);\n const files: string[] = [];\n\n // Skip common temporary/cache files and git repos that change frequently\n const skipPatterns = [\n '.DS_Store',\n 'Thumbs.db',\n '.git', // Skip git directories to prevent nested repos\n '.gitignore',\n 'node_modules',\n '.cache',\n '__pycache__',\n '*.pyc',\n '*.swp',\n '*.tmp',\n '.npmrc',\n 'package-lock.json',\n 'yarn.lock',\n 'pnpm-lock.yaml',\n ];\n\n let entries;\n try {\n entries = await readdir(expandedPath, { withFileTypes: true });\n } catch (error) {\n // Handle permission errors and other read failures gracefully\n return files;\n }\n\n for (const entry of entries) {\n const entryPath = join(expandedPath, entry.name);\n \n const shouldSkip = skipPatterns.some(pattern => {\n if (pattern.includes('*')) {\n // Escape special regex characters (especially .) before replacing * with .*\n const escapedPattern = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n const regex = new RegExp('^' + escapedPattern + '$');\n return regex.test(entry.name);\n }\n return entry.name === pattern;\n });\n \n if (shouldSkip) {\n continue;\n }\n\n try {\n // Use lstat to detect symlinks (stat follows symlinks, lstat doesn't)\n const lstats = await lstat(entryPath);\n\n // Skip symlinks to prevent infinite recursion loops\n if (lstats.isSymbolicLink()) {\n continue;\n }\n\n if (entry.isDirectory()) {\n const subFiles = await getDirectoryFiles(entryPath);\n files.push(...subFiles);\n } else if (entry.isFile()) {\n files.push(entryPath);\n }\n } catch {\n // Skip entries we can't access (permission errors, etc.)\n continue;\n }\n }\n\n return files.sort();\n};\n\nexport const getDirectoryFileCount = async (dirpath: string): Promise<number> => {\n const files = await getDirectoryFiles(dirpath);\n return files.length;\n};\n\nexport const copyFileOrDir = async (\n source: string,\n destination: string,\n options?: { overwrite?: boolean }\n): Promise<CopyResult> => {\n const expandedSource = expandPath(source);\n const expandedDest = expandPath(destination);\n\n if (!(await pathExists(expandedSource))) {\n throw new FileNotFoundError(source);\n }\n\n // Ensure destination directory exists\n await ensureDir(dirname(expandedDest));\n\n const sourceIsDir = await isDirectory(expandedSource);\n\n try {\n const shouldOverwrite = options?.overwrite ?? true;\n\n if (sourceIsDir) {\n // Copy directory but skip .git and other problematic files\n await copy(expandedSource, expandedDest, { \n overwrite: shouldOverwrite,\n filter: (src: string) => {\n const name = basename(src);\n // Skip .git directories, node_modules, and cache directories\n const skipDirs = ['.git', 'node_modules', '.cache', '__pycache__', '.DS_Store'];\n return !skipDirs.includes(name);\n }\n });\n const fileCount = await getDirectoryFileCount(expandedDest);\n const files = await getDirectoryFiles(expandedDest);\n let totalSize = 0;\n for (const file of files) {\n const stats = await stat(file);\n totalSize += stats.size;\n }\n return { source: expandedSource, destination: expandedDest, fileCount, totalSize };\n } else {\n // Use COPYFILE_EXCL flag to prevent overwriting when overwrite is false\n // If overwrite is true (default), use mode 0 which allows overwriting\n const copyFlags = shouldOverwrite ? 0 : constants.COPYFILE_EXCL;\n await copyFile(expandedSource, expandedDest, copyFlags);\n const stats = await stat(expandedDest);\n return { source: expandedSource, destination: expandedDest, fileCount: 1, totalSize: stats.size };\n }\n } catch (error) {\n throw new PermissionError(destination, 'write');\n }\n};\n\nexport const createSymlink = async (\n target: string,\n linkPath: string,\n options?: { overwrite?: boolean }\n): Promise<void> => {\n const expandedTarget = expandPath(target);\n const expandedLink = expandPath(linkPath);\n\n if (!(await pathExists(expandedTarget))) {\n throw new FileNotFoundError(target);\n }\n\n // Ensure link parent directory exists\n await ensureDir(dirname(expandedLink));\n\n // Remove existing file/symlink if overwrite is true\n if (options?.overwrite && (await pathExists(expandedLink))) {\n await unlink(expandedLink);\n }\n\n try {\n await symlink(expandedTarget, expandedLink);\n } catch (error) {\n throw new PermissionError(linkPath, 'create symlink');\n }\n};\n\nexport const deleteFileOrDir = async (filepath: string): Promise<void> => {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n return; // Already deleted\n }\n\n try {\n if (await isDirectory(expandedPath)) {\n await rm(expandedPath, { recursive: true });\n } else {\n await unlink(expandedPath);\n }\n } catch (error) {\n throw new PermissionError(filepath, 'delete');\n }\n};\n\nexport const ensureDirectory = async (dirpath: string): Promise<void> => {\n const expandedPath = expandPath(dirpath);\n await ensureDir(expandedPath);\n};\n\nexport const moveFile = async (\n source: string,\n destination: string,\n options?: { overwrite?: boolean }\n): Promise<void> => {\n await copyFileOrDir(source, destination, options);\n await deleteFileOrDir(source);\n};\n\nexport const hasFileChanged = async (\n file1: string,\n file2: string\n): Promise<boolean> => {\n const expandedFile1 = expandPath(file1);\n const expandedFile2 = expandPath(file2);\n\n // If either doesn't exist, they're different\n if (!(await pathExists(expandedFile1)) || !(await pathExists(expandedFile2))) {\n return true;\n }\n\n const checksum1 = await getFileChecksum(expandedFile1);\n const checksum2 = await getFileChecksum(expandedFile2);\n\n return checksum1 !== checksum2;\n};\n\nexport const getFilePermissions = async (filepath: string): Promise<string> => {\n const expandedPath = expandPath(filepath);\n const stats = await stat(expandedPath);\n return (stats.mode & 0o777).toString(8).padStart(3, '0');\n};\n\nexport const setFilePermissions = async (filepath: string, mode: string): Promise<void> => {\n const expandedPath = expandPath(filepath);\n const { chmod } = await import('fs/promises');\n await chmod(expandedPath, parseInt(mode, 8));\n};\n\nexport const formatBytes = (bytes: number): string => {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;\n};\n\n// ============================================================================\n// File Size Utilities for Large File Detection\n// ============================================================================\n\nexport const SIZE_WARN_THRESHOLD = 50 * 1024 * 1024; // 50MB\nexport const SIZE_BLOCK_THRESHOLD = 100 * 1024 * 1024; // 100MB\n\n/**\n * Get total size of a file or directory recursively\n */\nexport const getFileSizeRecursive = async (filepath: string): Promise<number> => {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n return 0;\n }\n\n const stats = await stat(expandedPath);\n\n if (!stats.isDirectory()) {\n return stats.size;\n }\n\n // Directory: sum all file sizes\n const files = await getDirectoryFiles(expandedPath);\n let totalSize = 0;\n\n for (const file of files) {\n try {\n const fileStats = await stat(file);\n totalSize += fileStats.size;\n } catch {\n // Skip files we can't access\n continue;\n }\n }\n\n return totalSize;\n};\n\n/**\n * Format file size in human-readable format (e.g., \"50.2 MB\")\n * Adds validation to handle invalid/negative values safely\n */\nexport const formatFileSize = (bytes: number): string => {\n // Normalize invalid or negative values to 0 to avoid surprising output\n if (!Number.isFinite(bytes) || bytes < 0) {\n bytes = 0;\n }\n return formatBytes(bytes);\n};\n\n/**\n * Check if file size exceeds warning or blocking thresholds\n */\nexport const checkFileSizeThreshold = async (\n filepath: string\n): Promise<{ warn: boolean; block: boolean; size: number }> => {\n const size = await getFileSizeRecursive(filepath);\n\n return {\n warn: size >= SIZE_WARN_THRESHOLD,\n block: size >= SIZE_BLOCK_THRESHOLD,\n size,\n };\n};\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport { expandPath, collapsePath, getDestinationPath, getRelativeDestination, generateFileId, sanitizeFilename, detectCategory } from './paths.js';\nimport { addFileToManifest } from './manifest.js';\nimport { copyFileOrDir, createSymlink, getFileChecksum, getFileInfo } from './files.js';\nimport { loadConfig } from './config.js';\nimport { CATEGORIES } from '../constants.js';\nimport { ensureDir } from 'fs-extra';\nimport { dirname } from 'path';\nimport type { FileStrategy } from '../types.js';\n\nexport interface FileToTrack {\n path: string;\n category?: string;\n}\n\nexport interface FileTrackingOptions {\n /**\n * Show category icons after file names\n */\n showCategory?: boolean;\n\n /**\n * Custom strategy (copy, symlink, etc.)\n */\n strategy?: FileStrategy;\n\n // TODO: Encryption and templating are planned for a future version\n // /**\n // * Encrypt files\n // */\n // encrypt?: boolean;\n //\n // /**\n // * Treat as template\n // */\n // template?: boolean;\n\n /**\n * Delay between file operations in milliseconds\n * Automatically reduced for large batches (>=50 files)\n */\n delayBetween?: number;\n\n /**\n * Action verb for display (e.g., \"Tracking\", \"Adding\", \"Processing\")\n */\n actionVerb?: string;\n\n /**\n * Callback called after each file is processed\n */\n onProgress?: (current: number, total: number) => void;\n}\n\nexport interface FileTrackingResult {\n succeeded: number;\n failed: number;\n errors: Array<{ path: string; error: Error }>;\n sensitiveFiles: string[];\n}\n\n/**\n * Pattern matching for sensitive files\n */\nconst SENSITIVE_FILE_PATTERNS = [\n /^\\.netrc$/,\n /^\\.aws\\/credentials$/,\n /^\\.docker\\/config\\.json$/,\n /^\\.npmrc$/,\n /^\\.pypirc$/,\n /^\\.kube\\/config$/,\n /^\\.ssh\\/config$/,\n /^\\.gnupg\\//,\n /credentials/i,\n /secrets?/i,\n /tokens?\\.json$/i,\n /\\.env$/,\n /\\.env\\./,\n];\n\n/**\n * Check if a path contains potentially sensitive data\n */\nconst isSensitiveFile = (path: string): boolean => {\n const pathToTest = path.startsWith('~/') ? path.slice(2) : path;\n for (const pattern of SENSITIVE_FILE_PATTERNS) {\n if (pattern.test(pathToTest)) {\n return true;\n }\n }\n return false;\n};\n\n/**\n * Shared file tracking logic used by add, scan, and init commands.\n * Processes files one by one with beautiful progress display.\n * \n * @param files - Array of files to track with their paths and optional categories\n * @param tuckDir - Path to the tuck directory\n * @param options - Options for tracking behavior and display\n * @returns Result containing success/failure counts and accumulated errors\n */\nexport const trackFilesWithProgress = async (\n files: FileToTrack[],\n tuckDir: string,\n options: FileTrackingOptions = {}\n): Promise<FileTrackingResult> => {\n const {\n showCategory = true,\n strategy: customStrategy,\n // TODO: Encryption and templating are planned for a future version\n // encrypt = false,\n // template = false,\n actionVerb = 'Tracking',\n onProgress,\n } = options;\n\n // Adaptive delay: reduce delay for large batches\n let { delayBetween } = options;\n if (delayBetween === undefined) {\n delayBetween = files.length >= 50 ? 10 : 30; // 10ms for large batches, 30ms for small\n }\n\n const config = await loadConfig(tuckDir);\n const strategy: FileStrategy = customStrategy || config.files.strategy || 'copy';\n const total = files.length;\n const errors: Array<{ path: string; error: Error }> = [];\n const sensitiveFiles: string[] = [];\n let succeeded = 0;\n\n console.log();\n console.log(chalk.bold.cyan(`${actionVerb} ${total} ${total === 1 ? 'file' : 'files'}...`));\n console.log(chalk.dim('─'.repeat(50)));\n console.log();\n\n for (let i = 0; i < files.length; i++) {\n const file = files[i];\n const expandedPath = expandPath(file.path);\n const indexStr = chalk.dim(`[${i + 1}/${total}]`);\n const category = file.category || detectCategory(expandedPath);\n const filename = sanitizeFilename(expandedPath);\n const categoryInfo = CATEGORIES[category];\n const icon = categoryInfo?.icon || '○';\n\n // Show spinner while processing\n const spinner = ora({\n text: `${indexStr} ${actionVerb} ${chalk.cyan(collapsePath(file.path))}`,\n color: 'cyan',\n spinner: 'dots',\n indent: 2,\n }).start();\n\n try {\n // Get destination path\n const destination = getDestinationPath(tuckDir, category, filename);\n\n // Ensure category directory exists\n await ensureDir(dirname(destination));\n\n // Copy or symlink based on strategy\n if (strategy === 'symlink') {\n // Create symlink from destination to source (repo points to original)\n await createSymlink(expandedPath, destination, { overwrite: true });\n } else {\n // Default: copy file into the repository\n await copyFileOrDir(expandedPath, destination, { overwrite: true });\n }\n\n // Get file info\n const checksum = await getFileChecksum(destination);\n const info = await getFileInfo(expandedPath);\n const now = new Date().toISOString();\n\n // Generate unique ID\n const id = generateFileId(file.path);\n\n // Add to manifest\n await addFileToManifest(tuckDir, id, {\n source: collapsePath(file.path),\n destination: getRelativeDestination(category, filename),\n category,\n strategy,\n // TODO: Encryption and templating are planned for a future version\n encrypted: false,\n template: false,\n permissions: info.permissions,\n added: now,\n modified: now,\n checksum,\n });\n\n spinner.stop();\n const categoryStr = showCategory ? chalk.dim(` ${icon} ${category}`) : '';\n console.log(` ${chalk.green('✓')} ${indexStr} ${collapsePath(file.path)}${categoryStr}`);\n\n // Track sensitive files for warning at the end\n if (isSensitiveFile(collapsePath(file.path))) {\n sensitiveFiles.push(file.path);\n }\n\n succeeded++;\n\n // Call progress callback\n if (onProgress) {\n onProgress(i + 1, total);\n }\n\n // Small delay for visual effect (unless it's the last item)\n if (i < files.length - 1 && delayBetween > 0) {\n await new Promise(resolve => setTimeout(resolve, delayBetween));\n }\n } catch (error) {\n spinner.stop();\n const errorObj = error instanceof Error ? error : new Error(String(error));\n errors.push({ path: file.path, error: errorObj });\n console.log(` ${chalk.red('✗')} ${indexStr} ${collapsePath(file.path)} ${chalk.red('- failed')}`);\n }\n }\n\n // Show summary\n console.log();\n if (succeeded > 0) {\n console.log(chalk.green('✓'), chalk.bold(`Tracked ${succeeded} ${succeeded === 1 ? 'file' : 'files'} successfully`));\n }\n\n // Show accumulated errors if any\n if (errors.length > 0) {\n console.log();\n console.log(chalk.red('✗'), chalk.bold(`Failed to track ${errors.length} ${errors.length === 1 ? 'file' : 'files'}:`));\n for (const { path, error } of errors) {\n console.log(chalk.dim(` • ${collapsePath(path)}: ${error.message}`));\n }\n }\n\n // Warn about sensitive files at the end (not inline to avoid clutter)\n if (sensitiveFiles.length > 0) {\n console.log();\n console.log(chalk.yellow('⚠'), chalk.yellow('Warning: Some files may contain sensitive data:'));\n for (const path of sensitiveFiles) {\n console.log(chalk.dim(` • ${collapsePath(path)}`));\n }\n console.log(chalk.dim(' Make sure your repository is private!'));\n }\n\n return {\n succeeded,\n failed: errors.length,\n errors,\n sensitiveFiles,\n };\n};\n","import { join } from 'path';\nimport { readdir, rm } from 'fs/promises';\nimport { copy, ensureDir, pathExists } from 'fs-extra';\nimport { BACKUP_DIR } from '../constants.js';\nimport { expandPath, collapsePath, pathExists as checkPathExists } from './paths.js';\n\nexport interface BackupInfo {\n path: string;\n date: Date;\n files: string[];\n}\n\nexport interface BackupResult {\n originalPath: string;\n backupPath: string;\n date: Date;\n}\n\nconst getBackupDir = (): string => {\n return expandPath(BACKUP_DIR);\n};\n\nconst formatDateForBackup = (date: Date): string => {\n return date.toISOString().slice(0, 10); // YYYY-MM-DD\n};\n\nconst getTimestampedBackupDir = (date: Date): string => {\n const backupRoot = getBackupDir();\n const timestamp = formatDateForBackup(date);\n return join(backupRoot, timestamp);\n};\n\nexport const createBackup = async (\n sourcePath: string,\n customBackupDir?: string\n): Promise<BackupResult> => {\n const expandedSource = expandPath(sourcePath);\n const date = new Date();\n\n if (!(await checkPathExists(expandedSource))) {\n throw new Error(`Source path does not exist: ${sourcePath}`);\n }\n\n // Create backup directory with date\n const backupRoot = customBackupDir\n ? expandPath(customBackupDir)\n : getTimestampedBackupDir(date);\n await ensureDir(backupRoot);\n\n // Generate backup filename that preserves structure\n const collapsed = collapsePath(expandedSource);\n const backupName = collapsed\n .replace(/^~\\//, '')\n .replace(/\\//g, '_')\n .replace(/^\\./, 'dot-');\n\n // Add timestamp to handle multiple backups of same file in a day\n const timestamp = date.toISOString().replace(/[:.]/g, '-').slice(11, 19);\n const backupPath = join(backupRoot, `${backupName}_${timestamp}`);\n\n await copy(expandedSource, backupPath, { overwrite: true });\n\n return {\n originalPath: expandedSource,\n backupPath,\n date,\n };\n};\n\nexport const createMultipleBackups = async (\n sourcePaths: string[],\n customBackupDir?: string\n): Promise<BackupResult[]> => {\n const results: BackupResult[] = [];\n\n for (const path of sourcePaths) {\n const result = await createBackup(path, customBackupDir);\n results.push(result);\n }\n\n return results;\n};\n\nexport const listBackups = async (): Promise<BackupInfo[]> => {\n const backupRoot = getBackupDir();\n\n if (!(await pathExists(backupRoot))) {\n return [];\n }\n\n const backups: BackupInfo[] = [];\n const dateDirs = await readdir(backupRoot, { withFileTypes: true });\n\n for (const dateDir of dateDirs) {\n if (!dateDir.isDirectory()) continue;\n\n const datePath = join(backupRoot, dateDir.name);\n const files = await readdir(datePath);\n\n // Parse date from directory name\n const dateMatch = dateDir.name.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n if (!dateMatch) continue;\n\n const date = new Date(`${dateMatch[1]}-${dateMatch[2]}-${dateMatch[3]}`);\n\n backups.push({\n path: datePath,\n date,\n files: files.map((f) => join(datePath, f)),\n });\n }\n\n // Sort by date, newest first\n return backups.sort((a, b) => b.date.getTime() - a.date.getTime());\n};\n\nexport const getBackupsByDate = async (date: Date): Promise<string[]> => {\n const backupDir = getTimestampedBackupDir(date);\n\n if (!(await pathExists(backupDir))) {\n return [];\n }\n\n const files = await readdir(backupDir);\n return files.map((f) => join(backupDir, f));\n};\n\nexport const restoreBackup = async (backupPath: string, targetPath: string): Promise<void> => {\n const expandedBackup = expandPath(backupPath);\n const expandedTarget = expandPath(targetPath);\n\n if (!(await checkPathExists(expandedBackup))) {\n throw new Error(`Backup not found: ${backupPath}`);\n }\n\n // Create backup of current state before restoring\n if (await checkPathExists(expandedTarget)) {\n await createBackup(expandedTarget);\n }\n\n await copy(expandedBackup, expandedTarget, { overwrite: true });\n};\n\nexport const deleteBackup = async (backupPath: string): Promise<void> => {\n const expandedPath = expandPath(backupPath);\n\n if (await checkPathExists(expandedPath)) {\n await rm(expandedPath, { recursive: true });\n }\n};\n\nexport const cleanOldBackups = async (daysToKeep: number): Promise<number> => {\n const backups = await listBackups();\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);\n\n let deletedCount = 0;\n\n for (const backup of backups) {\n if (backup.date < cutoffDate) {\n await rm(backup.path, { recursive: true });\n deletedCount++;\n }\n }\n\n return deletedCount;\n};\n\nexport const getBackupSize = async (): Promise<number> => {\n const backups = await listBackups();\n let totalSize = 0;\n\n for (const backup of backups) {\n for (const file of backup.files) {\n const { stat } = await import('fs/promises');\n try {\n const stats = await stat(file);\n totalSize += stats.size;\n } catch {\n // Ignore errors\n }\n }\n }\n\n return totalSize;\n};\n","import { exec } from 'child_process';\nimport { promisify } from 'util';\nimport chalk from 'chalk';\nimport { loadConfig } from './config.js';\nimport { logger } from '../ui/logger.js';\nimport { prompts } from '../ui/prompts.js';\n\nconst execAsync = promisify(exec);\n\nexport type HookType = 'preSync' | 'postSync' | 'preRestore' | 'postRestore';\n\nexport interface HookResult {\n success: boolean;\n output?: string;\n error?: string;\n skipped?: boolean;\n}\n\nexport interface HookOptions {\n silent?: boolean;\n skipHooks?: boolean;\n trustHooks?: boolean;\n}\n\n/**\n * SECURITY: This function executes shell commands from the configuration file.\n * When cloning from untrusted repositories, hooks could contain malicious commands.\n * We require explicit user confirmation before executing any hooks.\n */\nexport const runHook = async (\n hookType: HookType,\n tuckDir: string,\n options?: HookOptions\n): Promise<HookResult> => {\n // If hooks are explicitly disabled, skip execution\n if (options?.skipHooks) {\n return { success: true, skipped: true };\n }\n\n const config = await loadConfig(tuckDir);\n const command = config.hooks[hookType];\n\n if (!command) {\n return { success: true };\n }\n\n // SECURITY: Always show the hook command and require confirmation\n // unless trustHooks is explicitly set (for non-interactive/scripted use)\n if (!options?.trustHooks) {\n console.log();\n console.log(chalk.yellow.bold('WARNING: Hook Execution'));\n console.log(chalk.dim('─'.repeat(50)));\n console.log(chalk.white(`Hook type: ${chalk.cyan(hookType)}`));\n console.log(chalk.white('Command:'));\n console.log(chalk.red(` ${command}`));\n console.log(chalk.dim('─'.repeat(50)));\n console.log(\n chalk.yellow(\n 'SECURITY: Hooks can execute arbitrary commands on your system.'\n )\n );\n console.log(\n chalk.yellow(\n 'Only proceed if you trust the source of this configuration.'\n )\n );\n console.log();\n\n const confirmed = await prompts.confirm(\n 'Execute this hook?',\n false // Default to NO for safety\n );\n\n if (!confirmed) {\n logger.warning(`Hook ${hookType} skipped by user`);\n return { success: true, skipped: true };\n }\n }\n\n if (!options?.silent) {\n logger.dim(`Running ${hookType} hook...`);\n }\n\n try {\n const { stdout, stderr } = await execAsync(command, {\n cwd: tuckDir,\n timeout: 30000, // 30 second timeout\n env: {\n ...process.env,\n TUCK_DIR: tuckDir,\n TUCK_HOOK: hookType,\n },\n });\n\n if (stdout && !options?.silent) {\n logger.dim(stdout.trim());\n }\n\n if (stderr && !options?.silent) {\n logger.warning(stderr.trim());\n }\n\n return { success: true, output: stdout };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (!options?.silent) {\n logger.error(`Hook ${hookType} failed: ${errorMessage}`);\n }\n\n return { success: false, error: errorMessage };\n }\n};\n\nexport const runPreSyncHook = async (\n tuckDir: string,\n options?: HookOptions\n): Promise<HookResult> => {\n return runHook('preSync', tuckDir, options);\n};\n\nexport const runPostSyncHook = async (\n tuckDir: string,\n options?: HookOptions\n): Promise<HookResult> => {\n return runHook('postSync', tuckDir, options);\n};\n\nexport const runPreRestoreHook = async (\n tuckDir: string,\n options?: HookOptions\n): Promise<HookResult> => {\n return runHook('preRestore', tuckDir, options);\n};\n\nexport const runPostRestoreHook = async (\n tuckDir: string,\n options?: HookOptions\n): Promise<HookResult> => {\n return runHook('postRestore', tuckDir, options);\n};\n\nexport const hasHook = async (hookType: HookType, tuckDir: string): Promise<boolean> => {\n const config = await loadConfig(tuckDir);\n return Boolean(config.hooks[hookType]);\n};\n\nexport const getHookCommand = async (\n hookType: HookType,\n tuckDir: string\n): Promise<string | undefined> => {\n const config = await loadConfig(tuckDir);\n return config.hooks[hookType];\n};\n\n/**\n * Check if any hooks are configured\n */\nexport const hasAnyHooks = async (tuckDir: string): Promise<boolean> => {\n const config = await loadConfig(tuckDir);\n return Boolean(\n config.hooks.preSync ||\n config.hooks.postSync ||\n config.hooks.preRestore ||\n config.hooks.postRestore\n );\n};\n\n/**\n * Get all configured hooks for display\n */\nexport const getAllHooks = async (\n tuckDir: string\n): Promise<Record<HookType, string | undefined>> => {\n const config = await loadConfig(tuckDir);\n return {\n preSync: config.hooks.preSync,\n postSync: config.hooks.postSync,\n preRestore: config.hooks.preRestore,\n postRestore: config.hooks.postRestore,\n };\n};\n","import { Command } from 'commander';\nimport { join } from 'path';\nimport { colors as c } from '../ui/theme.js';\nimport { chmod, stat } from 'fs/promises';\nimport { prompts, logger, withSpinner } from '../ui/index.js';\nimport { getTuckDir, expandPath, pathExists, collapsePath } from '../lib/paths.js';\nimport { loadManifest, getAllTrackedFiles, getTrackedFileBySource } from '../lib/manifest.js';\nimport { loadConfig } from '../lib/config.js';\nimport { copyFileOrDir, createSymlink } from '../lib/files.js';\nimport { createBackup } from '../lib/backup.js';\nimport { runPreRestoreHook, runPostRestoreHook, type HookOptions } from '../lib/hooks.js';\nimport { NotInitializedError, FileNotFoundError } from '../errors.js';\nimport { CATEGORIES } from '../constants.js';\nimport type { RestoreOptions } from '../types.js';\n\n/**\n * Fix permissions for SSH files after restore\n * SSH requires strict permissions: 700 for directories, 600 for private files\n */\nconst fixSSHPermissions = async (path: string): Promise<void> => {\n const expandedPath = expandPath(path);\n\n // Only fix permissions for SSH files\n // Check for files inside .ssh/ directory or the .ssh directory itself\n if (!path.includes('.ssh/') && !path.endsWith('.ssh')) {\n return;\n }\n\n try {\n const stats = await stat(expandedPath);\n\n if (stats.isDirectory()) {\n // Directories should be 700\n await chmod(expandedPath, 0o700);\n } else {\n // Files should be 600\n await chmod(expandedPath, 0o600);\n }\n } catch {\n // Ignore permission errors (might be on Windows)\n }\n};\n\n/**\n * Fix GPG permissions after restore\n */\nconst fixGPGPermissions = async (path: string): Promise<void> => {\n const expandedPath = expandPath(path);\n\n // Only fix permissions for GPG files\n // Check for files inside .gnupg/ directory or the .gnupg directory itself\n if (!path.includes('.gnupg/') && !path.endsWith('.gnupg')) {\n return;\n }\n\n try {\n const stats = await stat(expandedPath);\n\n if (stats.isDirectory()) {\n await chmod(expandedPath, 0o700);\n } else {\n await chmod(expandedPath, 0o600);\n }\n } catch {\n // Ignore permission errors\n }\n};\n\ninterface FileToRestore {\n id: string;\n source: string;\n destination: string;\n category: string;\n existsAtTarget: boolean;\n}\n\nconst prepareFilesToRestore = async (\n tuckDir: string,\n paths?: string[]\n): Promise<FileToRestore[]> => {\n const allFiles = await getAllTrackedFiles(tuckDir);\n const filesToRestore: FileToRestore[] = [];\n\n if (paths && paths.length > 0) {\n // Restore specific files\n for (const path of paths) {\n const expandedPath = expandPath(path);\n const collapsedPath = collapsePath(expandedPath);\n\n const tracked = await getTrackedFileBySource(tuckDir, collapsedPath);\n if (!tracked) {\n throw new FileNotFoundError(`Not tracked: ${path}`);\n }\n\n filesToRestore.push({\n id: tracked.id,\n source: tracked.file.source,\n destination: join(tuckDir, tracked.file.destination),\n category: tracked.file.category,\n existsAtTarget: await pathExists(expandedPath),\n });\n }\n } else {\n // Restore all files\n for (const [id, file] of Object.entries(allFiles)) {\n const targetPath = expandPath(file.source);\n filesToRestore.push({\n id,\n source: file.source,\n destination: join(tuckDir, file.destination),\n category: file.category,\n existsAtTarget: await pathExists(targetPath),\n });\n }\n }\n\n return filesToRestore;\n};\n\nconst restoreFiles = async (\n tuckDir: string,\n files: FileToRestore[],\n options: RestoreOptions\n): Promise<number> => {\n const config = await loadConfig(tuckDir);\n const useSymlink = options.symlink || config.files.strategy === 'symlink';\n const shouldBackup = options.backup ?? config.files.backupOnRestore;\n\n // Prepare hook options\n const hookOptions: HookOptions = {\n skipHooks: options.noHooks,\n trustHooks: options.trustHooks,\n };\n\n // Run pre-restore hook\n await runPreRestoreHook(tuckDir, hookOptions);\n\n let restoredCount = 0;\n\n for (const file of files) {\n const targetPath = expandPath(file.source);\n\n // Check if source exists in repository\n if (!(await pathExists(file.destination))) {\n logger.warning(`Source not found in repository: ${file.source}`);\n continue;\n }\n\n // Dry run - just show what would happen\n if (options.dryRun) {\n if (file.existsAtTarget) {\n logger.file('modify', `${file.source} (would overwrite)`);\n } else {\n logger.file('add', `${file.source} (would create)`);\n }\n continue;\n }\n\n // Create backup if needed\n if (shouldBackup && file.existsAtTarget) {\n await withSpinner(`Backing up ${file.source}...`, async () => {\n await createBackup(targetPath);\n });\n }\n\n // Restore file\n await withSpinner(`Restoring ${file.source}...`, async () => {\n if (useSymlink) {\n await createSymlink(file.destination, targetPath, { overwrite: true });\n } else {\n await copyFileOrDir(file.destination, targetPath, { overwrite: true });\n }\n\n // Fix permissions for sensitive files\n await fixSSHPermissions(file.source);\n await fixGPGPermissions(file.source);\n });\n\n restoredCount++;\n }\n\n // Run post-restore hook\n await runPostRestoreHook(tuckDir, hookOptions);\n\n return restoredCount;\n};\n\nconst runInteractiveRestore = async (tuckDir: string): Promise<void> => {\n prompts.intro('tuck restore');\n\n // Get all tracked files\n const files = await prepareFilesToRestore(tuckDir);\n\n if (files.length === 0) {\n prompts.log.warning('No files to restore');\n prompts.note(\"Run 'tuck add <path>' to track files first\", 'Tip');\n return;\n }\n\n // Let user select files to restore\n const fileOptions = files.map((file) => {\n const categoryConfig = CATEGORIES[file.category] || { icon: '📄' };\n const status = file.existsAtTarget ? c.yellow('(exists, will backup)') : '';\n\n return {\n value: file.id,\n label: `${categoryConfig.icon} ${file.source} ${status}`,\n hint: file.category,\n };\n });\n\n const selectedIds = await prompts.multiselect('Select files to restore:', fileOptions, {\n required: true,\n });\n\n if (selectedIds.length === 0) {\n prompts.cancel('No files selected');\n return;\n }\n\n const selectedFiles = files.filter((f) => selectedIds.includes(f.id));\n\n // Check for files that exist\n const existingFiles = selectedFiles.filter((f) => f.existsAtTarget);\n if (existingFiles.length > 0) {\n console.log();\n prompts.log.warning(\n `${existingFiles.length} file${existingFiles.length > 1 ? 's' : ''} will be backed up:`\n );\n existingFiles.forEach((f) => console.log(c.dim(` ${f.source}`)));\n console.log();\n }\n\n // Ask about strategy\n const useSymlink = await prompts.select('Restore method:', [\n { value: false, label: 'Copy files', hint: 'Recommended' },\n { value: true, label: 'Create symlinks', hint: 'Files stay in tuck repo' },\n ]);\n\n // Confirm\n const confirm = await prompts.confirm(\n `Restore ${selectedFiles.length} file${selectedFiles.length > 1 ? 's' : ''}?`,\n true\n );\n\n if (!confirm) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n // Restore\n const restoredCount = await restoreFiles(tuckDir, selectedFiles, {\n symlink: useSymlink as boolean,\n backup: true,\n });\n\n console.log();\n prompts.outro(`Restored ${restoredCount} file${restoredCount > 1 ? 's' : ''}`);\n};\n\n/**\n * Run restore programmatically (exported for use by other commands)\n */\nexport const runRestore = async (options: RestoreOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Run interactive restore when called programmatically with --all\n if (options.all) {\n // Prepare files to restore\n const files = await prepareFilesToRestore(tuckDir, undefined);\n\n if (files.length === 0) {\n logger.warning('No files to restore');\n return;\n }\n\n // Restore files with progress\n const restoredCount = await restoreFiles(tuckDir, files, options);\n\n logger.blank();\n logger.success(`Restored ${restoredCount} file${restoredCount > 1 ? 's' : ''}`);\n } else {\n await runInteractiveRestore(tuckDir);\n }\n};\n\nconst runRestoreCommand = async (paths: string[], options: RestoreOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // If no paths and no --all, run interactive\n if (paths.length === 0 && !options.all) {\n await runInteractiveRestore(tuckDir);\n return;\n }\n\n // Prepare files to restore\n const files = await prepareFilesToRestore(tuckDir, options.all ? undefined : paths);\n\n if (files.length === 0) {\n logger.warning('No files to restore');\n return;\n }\n\n // Show what will be restored\n if (options.dryRun) {\n logger.heading('Dry run - would restore:');\n } else {\n logger.heading('Restoring:');\n }\n\n // Restore files\n const restoredCount = await restoreFiles(tuckDir, files, options);\n\n logger.blank();\n\n if (options.dryRun) {\n logger.info(`Would restore ${files.length} file${files.length > 1 ? 's' : ''}`);\n } else {\n logger.success(`Restored ${restoredCount} file${restoredCount > 1 ? 's' : ''}`);\n }\n};\n\nexport const restoreCommand = new Command('restore')\n .description('Restore dotfiles to the system')\n .argument('[paths...]', 'Paths to restore (or use --all)')\n .option('-a, --all', 'Restore all tracked files')\n .option('--symlink', 'Create symlinks instead of copies')\n .option('--backup', 'Backup existing files before restore')\n .option('--no-backup', 'Skip backup of existing files')\n .option('--dry-run', 'Show what would be done')\n .option('--no-hooks', 'Skip execution of pre/post restore hooks')\n .option('--trust-hooks', 'Trust and run hooks without confirmation (use with caution)')\n .action(async (paths: string[], options: RestoreOptions) => {\n await runRestoreCommand(paths, options);\n });\n","import { join } from 'path';\nimport { readFile, writeFile, appendFile } from 'fs/promises';\nimport { pathExists, expandPath, collapsePath } from './paths.js';\n\nconst TUCKIGNORE_FILENAME = '.tuckignore';\n\nconst TUCKIGNORE_HEADER = `# .tuckignore - Files to exclude from tracking\n# One exact file path per line (no globs)\n# Lines starting with # are comments\n#\n# Example:\n# ~/bin/large-binary\n# ~/.docker/config.json\n`;\n\n/**\n * Get the path to .tuckignore file\n */\nexport const getTuckignorePath = (tuckDir: string): string => {\n return join(tuckDir, TUCKIGNORE_FILENAME);\n};\n\n/**\n * Load and parse .tuckignore file\n * Returns a Set of collapsed paths (with ~/ prefix)\n */\nexport const loadTuckignore = async (tuckDir: string): Promise<Set<string>> => {\n const ignorePath = getTuckignorePath(tuckDir);\n const ignoredPaths = new Set<string>();\n\n if (!(await pathExists(ignorePath))) {\n return ignoredPaths;\n }\n\n try {\n const content = await readFile(ignorePath, 'utf-8');\n const lines = content.split('\\n');\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith('#')) {\n continue;\n }\n\n // Expand and then collapse to normalize the path\n const expanded = expandPath(trimmed);\n const collapsed = collapsePath(expanded);\n ignoredPaths.add(collapsed);\n }\n } catch {\n // If the file can't be read, treat it as having no ignore rules.\n // This is intentionally non-fatal as it allows operation when .tuckignore\n // doesn't exist or has permission issues.\n }\n\n return ignoredPaths;\n};\n\n/**\n * Save paths to .tuckignore file\n * Overwrites the entire file\n */\nexport const saveTuckignore = async (tuckDir: string, paths: string[]): Promise<void> => {\n const ignorePath = getTuckignorePath(tuckDir);\n \n // Sort paths for consistent output\n const sortedPaths = [...paths].sort();\n \n const content = TUCKIGNORE_HEADER + '\\n' + sortedPaths.join('\\n') + '\\n';\n \n await writeFile(ignorePath, content, 'utf-8');\n};\n\n/**\n * Add a path to .tuckignore file\n * Appends to the file if it exists, creates it if not\n */\nexport const addToTuckignore = async (tuckDir: string, path: string): Promise<void> => {\n const ignorePath = getTuckignorePath(tuckDir);\n \n // Normalize path to use ~/ prefix\n const expanded = expandPath(path);\n const collapsed = collapsePath(expanded);\n\n // Check if already ignored\n const existingPaths = await loadTuckignore(tuckDir);\n if (existingPaths.has(collapsed)) {\n return; // Already in the ignore file\n }\n\n // If file doesn't exist, create it with header\n if (!(await pathExists(ignorePath))) {\n await writeFile(ignorePath, TUCKIGNORE_HEADER + '\\n', 'utf-8');\n }\n\n // Append the path\n await appendFile(ignorePath, collapsed + '\\n', 'utf-8');\n};\n\n/**\n * Check if a path is in .tuckignore\n */\nexport const isIgnored = async (tuckDir: string, path: string): Promise<boolean> => {\n const ignoredPaths = await loadTuckignore(tuckDir);\n \n // Normalize path for comparison\n const expanded = expandPath(path);\n const collapsed = collapsePath(expanded);\n \n return ignoredPaths.has(collapsed);\n};\n\n/**\n * Remove a path from .tuckignore\n */\nexport const removeFromTuckignore = async (tuckDir: string, path: string): Promise<void> => {\n const ignorePath = getTuckignorePath(tuckDir);\n \n if (!(await pathExists(ignorePath))) {\n return; // Nothing to remove\n }\n\n // Normalize path\n const expanded = expandPath(path);\n const collapsed = collapsePath(expanded);\n\n // Load all paths\n const ignoredPaths = await loadTuckignore(tuckDir);\n ignoredPaths.delete(collapsed);\n\n // Save back\n await saveTuckignore(tuckDir, Array.from(ignoredPaths));\n};\n\n/**\n * Get all ignored paths\n */\nexport const getIgnoredPaths = async (tuckDir: string): Promise<string[]> => {\n const ignoredPaths = await loadTuckignore(tuckDir);\n return Array.from(ignoredPaths).sort();\n};\n\n","/**\n * Secret detection patterns for tuck\n *\n * This module defines regex patterns for detecting various types of secrets\n * including API keys, tokens, private keys, and credentials.\n */\n\nexport type SecretSeverity = 'critical' | 'high' | 'medium' | 'low';\n\nexport interface SecretPattern {\n id: string;\n name: string;\n pattern: RegExp;\n severity: SecretSeverity;\n description: string;\n placeholder: string;\n}\n\n// ============================================================================\n// Cloud Provider Patterns\n// ============================================================================\n\nexport const CLOUD_PROVIDER_PATTERNS: SecretPattern[] = [\n {\n id: 'aws-access-key',\n name: 'AWS Access Key ID',\n pattern: /\\b(AKIA[0-9A-Z]{16})\\b/g,\n severity: 'critical',\n description: 'AWS Access Key ID',\n placeholder: 'AWS_ACCESS_KEY_ID',\n },\n {\n id: 'aws-secret-key',\n name: 'AWS Secret Access Key',\n // AWS secret keys are 40 characters, base64-ish\n // Look for context clues (assignment to aws_secret, etc.)\n pattern: /(?:aws_secret_access_key|aws_secret|secret_access_key)\\s*[=:]\\s*['\"]?([A-Za-z0-9/+=]{40})['\"]?/gi,\n severity: 'critical',\n description: 'AWS Secret Access Key',\n placeholder: 'AWS_SECRET_ACCESS_KEY',\n },\n {\n id: 'aws-session-token',\n name: 'AWS Session Token',\n pattern: /(?:aws_session_token)\\s*[=:]\\s*['\"]?([A-Za-z0-9/+=]{100,1000})['\"]?/gi,\n severity: 'critical',\n description: 'AWS Session Token',\n placeholder: 'AWS_SESSION_TOKEN',\n },\n {\n id: 'gcp-api-key',\n name: 'Google Cloud API Key',\n pattern: /\\b(AIza[0-9A-Za-z_-]{35})\\b/g,\n severity: 'critical',\n description: 'Google Cloud API Key',\n placeholder: 'GCP_API_KEY',\n },\n {\n id: 'gcp-service-account',\n name: 'GCP Service Account',\n // Detects the private_key field in service account JSON\n pattern: /-----BEGIN PRIVATE KEY-----[A-Za-z0-9+/=\\s]+-----END PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'GCP Service Account Private Key',\n placeholder: 'GCP_SERVICE_ACCOUNT_KEY',\n },\n {\n id: 'azure-subscription-key',\n name: 'Azure Subscription Key',\n // Require Azure-specific context (common variable or header names) to reduce false positives.\n // Matches patterns like:\n // const AZURE_SUBSCRIPTION_KEY = \"0123abcd...\"; \n // \"Ocp-Apim-Subscription-Key\": \"0123abcd...\";\n pattern: /\\b(?:azure[_-]?(?:subscription[_-]?key|key)|subscription[_-]?key|Ocp-Apim-Subscription-Key)\\b\\s*[:=]\\s*['\"]?([a-f0-9]{32})['\"]?/gi,\n severity: 'medium', // Lower severity due to remaining false positive risk\n description: 'Azure Subscription Key (with context)',\n placeholder: 'AZURE_SUBSCRIPTION_KEY',\n },\n {\n id: 'digitalocean-token',\n name: 'DigitalOcean Token',\n pattern: /\\b(dop_v1_[a-f0-9]{64})\\b/g,\n severity: 'critical',\n description: 'DigitalOcean Personal Access Token',\n placeholder: 'DIGITALOCEAN_TOKEN',\n },\n {\n id: 'digitalocean-oauth',\n name: 'DigitalOcean OAuth Token',\n pattern: /\\b(doo_v1_[a-f0-9]{64})\\b/g,\n severity: 'critical',\n description: 'DigitalOcean OAuth Token',\n placeholder: 'DIGITALOCEAN_OAUTH_TOKEN',\n },\n {\n id: 'digitalocean-refresh',\n name: 'DigitalOcean Refresh Token',\n pattern: /\\b(dor_v1_[a-f0-9]{64})\\b/g,\n severity: 'critical',\n description: 'DigitalOcean Refresh Token',\n placeholder: 'DIGITALOCEAN_REFRESH_TOKEN',\n },\n];\n\n// ============================================================================\n// API Token Patterns\n// ============================================================================\n\nexport const API_TOKEN_PATTERNS: SecretPattern[] = [\n // GitHub\n {\n id: 'github-pat',\n name: 'GitHub Personal Access Token',\n pattern: /\\b(ghp_[A-Za-z0-9]{36,255})\\b/g,\n severity: 'critical',\n description: 'GitHub Personal Access Token',\n placeholder: 'GITHUB_TOKEN',\n },\n {\n id: 'github-oauth',\n name: 'GitHub OAuth Token',\n pattern: /\\b(gho_[A-Za-z0-9]{36,255})\\b/g,\n severity: 'critical',\n description: 'GitHub OAuth Access Token',\n placeholder: 'GITHUB_OAUTH_TOKEN',\n },\n {\n id: 'github-user-to-server',\n name: 'GitHub User-to-Server Token',\n pattern: /\\b(ghu_[A-Za-z0-9]{36,255})\\b/g,\n severity: 'critical',\n description: 'GitHub User-to-Server Token',\n placeholder: 'GITHUB_USER_TOKEN',\n },\n {\n id: 'github-server-to-server',\n name: 'GitHub Server-to-Server Token',\n pattern: /\\b(ghs_[A-Za-z0-9]{36,255})\\b/g,\n severity: 'critical',\n description: 'GitHub Server-to-Server Token',\n placeholder: 'GITHUB_SERVER_TOKEN',\n },\n {\n id: 'github-refresh',\n name: 'GitHub Refresh Token',\n pattern: /\\b(ghr_[A-Za-z0-9]{36,255})\\b/g,\n severity: 'critical',\n description: 'GitHub Refresh Token',\n placeholder: 'GITHUB_REFRESH_TOKEN',\n },\n {\n id: 'github-fine-grained',\n name: 'GitHub Fine-Grained PAT',\n pattern: /\\b(github_pat_[A-Za-z0-9_]{22,255})\\b/g,\n severity: 'critical',\n description: 'GitHub Fine-Grained Personal Access Token',\n placeholder: 'GITHUB_FINE_GRAINED_TOKEN',\n },\n\n // OpenAI\n {\n id: 'openai-api-key',\n name: 'OpenAI API Key',\n pattern: /\\b(sk-[A-Za-z0-9]{20,256}T3BlbkFJ[A-Za-z0-9]{20,256})\\b/g,\n severity: 'critical',\n description: 'OpenAI API Key (legacy format)',\n placeholder: 'OPENAI_API_KEY',\n },\n {\n id: 'openai-api-key-new',\n name: 'OpenAI API Key (new format)',\n pattern: /\\b(sk-proj-[A-Za-z0-9_-]{80,256})\\b/g,\n severity: 'critical',\n description: 'OpenAI API Key (project format)',\n placeholder: 'OPENAI_API_KEY',\n },\n {\n id: 'openai-api-key-org',\n name: 'OpenAI Organization Key',\n pattern: /\\b(sk-[A-Za-z0-9]{48,256})\\b/g,\n severity: 'critical',\n description: 'OpenAI API Key',\n placeholder: 'OPENAI_API_KEY',\n },\n\n // Anthropic\n {\n id: 'anthropic-api-key',\n name: 'Anthropic API Key',\n pattern: /\\b(sk-ant-api[a-zA-Z0-9_-]{90,256})\\b/g,\n severity: 'critical',\n description: 'Anthropic API Key',\n placeholder: 'ANTHROPIC_API_KEY',\n },\n\n // Slack\n {\n id: 'slack-bot-token',\n name: 'Slack Bot Token',\n pattern: /\\b(xoxb-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*)\\b/g,\n severity: 'critical',\n description: 'Slack Bot Token',\n placeholder: 'SLACK_BOT_TOKEN',\n },\n {\n id: 'slack-user-token',\n name: 'Slack User Token',\n pattern: /\\b(xoxp-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*)\\b/g,\n severity: 'critical',\n description: 'Slack User Token',\n placeholder: 'SLACK_USER_TOKEN',\n },\n {\n id: 'slack-app-token',\n name: 'Slack App Token',\n pattern: /\\b(xapp-[0-9]+-[A-Z0-9]+-[0-9]+-[a-z0-9]+)\\b/gi,\n severity: 'critical',\n description: 'Slack App-Level Token',\n placeholder: 'SLACK_APP_TOKEN',\n },\n {\n id: 'slack-webhook',\n name: 'Slack Webhook URL',\n pattern: /https:\\/\\/hooks\\.slack\\.com\\/services\\/T[A-Z0-9]+\\/B[A-Z0-9]+\\/[a-zA-Z0-9]+/g,\n severity: 'high',\n description: 'Slack Incoming Webhook URL',\n placeholder: 'SLACK_WEBHOOK_URL',\n },\n\n // Stripe\n {\n id: 'stripe-live-secret',\n name: 'Stripe Live Secret Key',\n pattern: /\\b(sk_live_[0-9a-zA-Z]{24,256})\\b/g,\n severity: 'critical',\n description: 'Stripe Live Secret Key',\n placeholder: 'STRIPE_SECRET_KEY',\n },\n {\n id: 'stripe-live-publishable',\n name: 'Stripe Live Publishable Key',\n pattern: /\\b(pk_live_[0-9a-zA-Z]{24,256})\\b/g,\n severity: 'high',\n description: 'Stripe Live Publishable Key',\n placeholder: 'STRIPE_PUBLISHABLE_KEY',\n },\n {\n id: 'stripe-test-secret',\n name: 'Stripe Test Secret Key',\n pattern: /\\b(sk_test_[0-9a-zA-Z]{24,256})\\b/g,\n severity: 'medium',\n description: 'Stripe Test Secret Key',\n placeholder: 'STRIPE_TEST_SECRET_KEY',\n },\n {\n id: 'stripe-restricted',\n name: 'Stripe Restricted Key',\n pattern: /\\b(rk_live_[0-9a-zA-Z]{24,256})\\b/g,\n severity: 'critical',\n description: 'Stripe Restricted API Key',\n placeholder: 'STRIPE_RESTRICTED_KEY',\n },\n\n // Twilio\n {\n id: 'twilio-api-key',\n name: 'Twilio API Key',\n pattern: /\\b(SK[0-9a-fA-F]{32})\\b/g,\n severity: 'critical',\n description: 'Twilio API Key',\n placeholder: 'TWILIO_API_KEY',\n },\n {\n id: 'twilio-account-sid',\n name: 'Twilio Account SID',\n pattern: /\\b(AC[0-9a-fA-F]{32})\\b/g,\n severity: 'high',\n description: 'Twilio Account SID',\n placeholder: 'TWILIO_ACCOUNT_SID',\n },\n\n // SendGrid\n {\n id: 'sendgrid-api-key',\n name: 'SendGrid API Key',\n pattern: /\\b(SG\\.[A-Za-z0-9_-]{22}\\.[A-Za-z0-9_-]{43})\\b/g,\n severity: 'critical',\n description: 'SendGrid API Key',\n placeholder: 'SENDGRID_API_KEY',\n },\n\n // Mailchimp\n {\n id: 'mailchimp-api-key',\n name: 'Mailchimp API Key',\n pattern: /\\b([a-f0-9]{32}-us[0-9]{1,2})\\b/g,\n severity: 'critical',\n description: 'Mailchimp API Key',\n placeholder: 'MAILCHIMP_API_KEY',\n },\n\n // npm\n {\n id: 'npm-access-token',\n name: 'npm Access Token',\n pattern: /\\b(npm_[A-Za-z0-9]{36})\\b/g,\n severity: 'critical',\n description: 'npm Access Token',\n placeholder: 'NPM_TOKEN',\n },\n\n // PyPI\n {\n id: 'pypi-api-token',\n name: 'PyPI API Token',\n pattern: /\\b(pypi-AgEIcHlwaS5vcmc[A-Za-z0-9_-]{50,256})\\b/g,\n severity: 'critical',\n description: 'PyPI API Token',\n placeholder: 'PYPI_TOKEN',\n },\n\n // Discord\n {\n id: 'discord-bot-token',\n name: 'Discord Bot Token',\n pattern: /\\b([MN][A-Za-z\\d]{23,256}\\.[\\w-]{6}\\.[\\w-]{27})\\b/g,\n severity: 'critical',\n description: 'Discord Bot Token',\n placeholder: 'DISCORD_BOT_TOKEN',\n },\n {\n id: 'discord-webhook',\n name: 'Discord Webhook URL',\n pattern: /https:\\/\\/discord(?:app)?\\.com\\/api\\/webhooks\\/[0-9]+\\/[A-Za-z0-9_-]+/g,\n severity: 'high',\n description: 'Discord Webhook URL',\n placeholder: 'DISCORD_WEBHOOK_URL',\n },\n\n // Telegram\n {\n id: 'telegram-bot-token',\n name: 'Telegram Bot Token',\n pattern: /\\b([0-9]{8,10}:[A-Za-z0-9_-]{35})\\b/g,\n severity: 'critical',\n description: 'Telegram Bot API Token',\n placeholder: 'TELEGRAM_BOT_TOKEN',\n },\n\n // Heroku\n {\n id: 'heroku-api-key',\n name: 'Heroku API Key',\n // Require Heroku-specific context to reduce UUID false positives\n pattern: /\\b(?:heroku[_-]?(?:api[_-]?key|key|token)|HEROKU_API_KEY)\\b\\s*[:=]\\s*['\"]?([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})['\"]?/gi,\n severity: 'high',\n description: 'Heroku API Key (UUID format with context)',\n placeholder: 'HEROKU_API_KEY',\n },\n\n // Datadog\n {\n id: 'datadog-api-key',\n name: 'Datadog API Key',\n // Require Datadog-specific context to reduce false positives\n pattern: /\\b(?:datadog[_-]?(?:api[_-]?key|key)|DD_API_KEY)\\b\\s*[:=]\\s*['\"]?([a-f0-9]{32})['\"]?/gi,\n severity: 'medium', // Lower due to false positives\n description: 'Datadog API Key (with context)',\n placeholder: 'DATADOG_API_KEY',\n },\n\n // CircleCI\n {\n id: 'circleci-token',\n name: 'CircleCI Personal Token',\n pattern: /\\b(circle-token-[a-f0-9]{40})\\b/g,\n severity: 'critical',\n description: 'CircleCI Personal API Token',\n placeholder: 'CIRCLECI_TOKEN',\n },\n\n // Travis CI\n {\n id: 'travis-token',\n name: 'Travis CI Token',\n // Require Travis-specific context to reduce false positives\n pattern: /\\b(?:travis[_-]?(?:token|key|api[_-]?key)|TRAVIS_TOKEN)\\b\\s*[:=]\\s*['\"]?([a-zA-Z0-9]{22})['\"]?/gi,\n severity: 'medium', // Lower due to false positives\n description: 'Travis CI Access Token (with context)',\n placeholder: 'TRAVIS_TOKEN',\n },\n\n // Firebase\n {\n id: 'firebase-api-key',\n name: 'Firebase API Key',\n pattern: /\\b(AIza[0-9A-Za-z_-]{35})\\b/g,\n severity: 'high',\n description: 'Firebase/Google API Key',\n placeholder: 'FIREBASE_API_KEY',\n },\n\n // Supabase\n {\n id: 'supabase-anon-key',\n name: 'Supabase Anon Key',\n pattern: /\\b(eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+)\\b/g,\n severity: 'high',\n description: 'Supabase Anonymous Key (JWT)',\n placeholder: 'SUPABASE_ANON_KEY',\n },\n\n // Vercel\n {\n id: 'vercel-token',\n name: 'Vercel Token',\n // Require Vercel-specific context to reduce false positives\n pattern: /\\b(?:vercel[_-]?(?:token|key)|VERCEL_TOKEN)\\b\\s*[:=]\\s*['\"]?([A-Za-z0-9]{24})['\"]?/gi,\n severity: 'medium', // Lower due to false positives\n description: 'Vercel Access Token (with context)',\n placeholder: 'VERCEL_TOKEN',\n },\n\n // Netlify\n {\n id: 'netlify-token',\n name: 'Netlify Personal Access Token',\n pattern: /\\b(nfp_[A-Za-z0-9]{40})\\b/g,\n severity: 'critical',\n description: 'Netlify Personal Access Token',\n placeholder: 'NETLIFY_TOKEN',\n },\n];\n\n// ============================================================================\n// Private Key Patterns\n// ============================================================================\n\nexport const PRIVATE_KEY_PATTERNS: SecretPattern[] = [\n {\n id: 'rsa-private-key',\n name: 'RSA Private Key',\n // Security: Length limit to prevent ReDoS\n pattern: /-----BEGIN RSA PRIVATE KEY-----[\\s\\S]{1,10000}?-----END RSA PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'RSA Private Key',\n placeholder: 'RSA_PRIVATE_KEY',\n },\n {\n id: 'openssh-private-key',\n name: 'OpenSSH Private Key',\n pattern: /-----BEGIN OPENSSH PRIVATE KEY-----[\\s\\S]{1,10000}?-----END OPENSSH PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'OpenSSH Private Key',\n placeholder: 'SSH_PRIVATE_KEY',\n },\n {\n id: 'dsa-private-key',\n name: 'DSA Private Key',\n pattern: /-----BEGIN DSA PRIVATE KEY-----[\\s\\S]{1,10000}?-----END DSA PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'DSA Private Key',\n placeholder: 'DSA_PRIVATE_KEY',\n },\n {\n id: 'ec-private-key',\n name: 'EC Private Key',\n pattern: /-----BEGIN EC PRIVATE KEY-----[\\s\\S]{1,10000}?-----END EC PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'EC Private Key',\n placeholder: 'EC_PRIVATE_KEY',\n },\n {\n id: 'generic-private-key',\n name: 'Generic Private Key',\n pattern: /-----BEGIN PRIVATE KEY-----[\\s\\S]{1,10000}?-----END PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'PKCS#8 Private Key',\n placeholder: 'PRIVATE_KEY',\n },\n {\n id: 'encrypted-private-key',\n name: 'Encrypted Private Key',\n pattern: /-----BEGIN ENCRYPTED PRIVATE KEY-----[\\s\\S]{1,10000}?-----END ENCRYPTED PRIVATE KEY-----/g,\n severity: 'high',\n description: 'Encrypted Private Key',\n placeholder: 'ENCRYPTED_PRIVATE_KEY',\n },\n {\n id: 'pgp-private-key',\n name: 'PGP Private Key',\n pattern: /-----BEGIN PGP PRIVATE KEY BLOCK-----[\\s\\S]{1,10000}?-----END PGP PRIVATE KEY BLOCK-----/g,\n severity: 'critical',\n description: 'PGP Private Key Block',\n placeholder: 'PGP_PRIVATE_KEY',\n },\n {\n id: 'putty-private-key',\n name: 'PuTTY Private Key',\n // Security: Length limit to prevent ReDoS\n pattern: /PuTTY-User-Key-File-[0-9]+:[\\s\\S]{1,5000}?Private-Lines:/g,\n severity: 'critical',\n description: 'PuTTY Private Key',\n placeholder: 'PUTTY_PRIVATE_KEY',\n },\n];\n\n// ============================================================================\n// Generic Secret Patterns\n// ============================================================================\n\nexport const GENERIC_PATTERNS: SecretPattern[] = [\n // Password assignments\n {\n id: 'password-assignment',\n name: 'Password Assignment',\n // Security: Upper bound to prevent ReDoS\n pattern: /(?:password|passwd|pwd|pass)\\s*[=:]\\s*['\"]([^'\"]{8,200})['\"]?/gi,\n severity: 'high',\n description: 'Password assigned in configuration',\n placeholder: 'PASSWORD',\n },\n {\n id: 'password-url',\n name: 'Password in URL',\n // Security: Upper bounds to prevent ReDoS\n pattern: /:\\/\\/[^:]{1,100}:([^@]{8,200})@/g,\n severity: 'critical',\n description: 'Password embedded in URL',\n placeholder: 'URL_PASSWORD',\n },\n\n // API key assignments\n {\n id: 'api-key-assignment',\n name: 'API Key Assignment',\n pattern: /(?:api[_-]?key|apikey)\\s*[=:]\\s*(?:['\"]([A-Za-z0-9_-]{16,256})['\"]|([A-Za-z0-9_-]{16,256}))/gi,\n severity: 'high',\n description: 'API key assigned in configuration',\n placeholder: 'API_KEY',\n },\n\n // Token assignments\n {\n id: 'token-assignment',\n name: 'Token Assignment',\n pattern: /(?:token|auth[_-]?token|access[_-]?token|bearer[_-]?token)\\s*[=:]\\s*(?:['\"]([A-Za-z0-9_.-]{20,256})['\"]|([A-Za-z0-9_.-]{20,256}))/gi,\n severity: 'high',\n description: 'Token assigned in configuration',\n placeholder: 'TOKEN',\n },\n\n // Secret assignments\n {\n id: 'secret-assignment',\n name: 'Secret Assignment',\n pattern: /(?:secret|client[_-]?secret|app[_-]?secret|secret[_-]?key)\\s*[=:]\\s*(?:['\"]([A-Za-z0-9_-]{16,256})['\"]|([A-Za-z0-9_-]{16,256}))/gi,\n severity: 'high',\n description: 'Secret assigned in configuration',\n placeholder: 'SECRET',\n },\n\n // Bearer tokens\n {\n id: 'bearer-token',\n name: 'Bearer Token',\n pattern: /Bearer\\s+([A-Za-z0-9_.-]{20,256})/g,\n severity: 'high',\n description: 'Bearer authentication token',\n placeholder: 'BEARER_TOKEN',\n },\n\n // Basic auth\n {\n id: 'basic-auth-header',\n name: 'Basic Auth Header',\n pattern: /Basic\\s+([A-Za-z0-9+/=]{20,256})/g,\n severity: 'high',\n description: 'Base64 encoded credentials',\n placeholder: 'BASIC_AUTH',\n },\n\n // Database connection strings\n // Security: All patterns have length limits to prevent ReDoS\n {\n id: 'postgres-connection',\n name: 'PostgreSQL Connection String',\n pattern: /postgres(?:ql)?:\\/\\/[^:]{1,100}:[^@]{1,200}@[^\\s'\"]{1,500}/gi,\n severity: 'critical',\n description: 'PostgreSQL connection string with credentials',\n placeholder: 'DATABASE_URL',\n },\n {\n id: 'mysql-connection',\n name: 'MySQL Connection String',\n pattern: /mysql:\\/\\/[^:]{1,100}:[^@]{1,200}@[^\\s'\"]{1,500}/gi,\n severity: 'critical',\n description: 'MySQL connection string with credentials',\n placeholder: 'DATABASE_URL',\n },\n {\n id: 'mongodb-connection',\n name: 'MongoDB Connection String',\n pattern: /mongodb(?:\\+srv)?:\\/\\/[^:]{1,100}:[^@]{1,200}@[^\\s'\"]{1,500}/gi,\n severity: 'critical',\n description: 'MongoDB connection string with credentials',\n placeholder: 'MONGODB_URI',\n },\n {\n id: 'redis-connection',\n name: 'Redis Connection String',\n pattern: /redis:\\/\\/[^:]{1,100}:[^@]{1,200}@[^\\s'\"]{1,500}/gi,\n severity: 'critical',\n description: 'Redis connection string with credentials',\n placeholder: 'REDIS_URL',\n },\n\n // JWT tokens (generic)\n {\n id: 'jwt-token',\n name: 'JWT Token',\n pattern: /\\beyJ[A-Za-z0-9_-]{10,256}\\.[A-Za-z0-9_-]{10,256}\\.[A-Za-z0-9_-]{10,256}\\b/g,\n severity: 'high',\n description: 'JSON Web Token',\n placeholder: 'JWT_TOKEN',\n },\n\n // Private key content (partial detection)\n {\n id: 'base64-private-key',\n name: 'Base64 Private Key Content',\n pattern: /MII[A-Za-z0-9+/]{60,512}={0,2}/g,\n severity: 'high',\n description: 'Base64 encoded private key content',\n placeholder: 'PRIVATE_KEY_CONTENT',\n },\n\n // Encryption keys\n {\n id: 'encryption-key',\n name: 'Encryption Key',\n pattern: /(?:encryption[_-]?key|aes[_-]?key|crypto[_-]?key)\\s*[=:]\\s*['\"]?([A-Fa-f0-9]{32,256})['\"]?/gi,\n severity: 'critical',\n description: 'Encryption key',\n placeholder: 'ENCRYPTION_KEY',\n },\n\n // SSH passphrase\n {\n id: 'ssh-passphrase',\n name: 'SSH Passphrase',\n pattern: /(?:ssh[_-]?passphrase|key[_-]?passphrase)\\s*[=:]\\s*['\"]([^'\"]+)['\"]?/gi,\n severity: 'critical',\n description: 'SSH key passphrase',\n placeholder: 'SSH_PASSPHRASE',\n },\n];\n\n// ============================================================================\n// Combine All Patterns\n// ============================================================================\n\nexport const ALL_SECRET_PATTERNS: SecretPattern[] = [\n ...CLOUD_PROVIDER_PATTERNS,\n ...API_TOKEN_PATTERNS,\n ...PRIVATE_KEY_PATTERNS,\n ...GENERIC_PATTERNS,\n];\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get patterns by severity level\n */\nexport const getPatternsBySeverity = (severity: SecretSeverity): SecretPattern[] => {\n return ALL_SECRET_PATTERNS.filter((p) => p.severity === severity);\n};\n\n/**\n * Get pattern by ID\n */\nexport const getPatternById = (id: string): SecretPattern | undefined => {\n return ALL_SECRET_PATTERNS.find((p) => p.id === id);\n};\n\n/**\n * Get patterns above a minimum severity\n * (critical > high > medium > low)\n */\nexport const getPatternsAboveSeverity = (minSeverity: SecretSeverity): SecretPattern[] => {\n const severityOrder: Record<SecretSeverity, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n };\n\n const minLevel = severityOrder[minSeverity];\n return ALL_SECRET_PATTERNS.filter((p) => severityOrder[p.severity] <= minLevel);\n};\n\n/**\n * Create a custom pattern\n */\nexport const createCustomPattern = (\n id: string,\n name: string,\n pattern: string,\n options?: {\n severity?: SecretSeverity;\n description?: string;\n placeholder?: string;\n flags?: string;\n }\n): SecretPattern => {\n return {\n id: `custom-${id}`,\n name,\n pattern: new RegExp(pattern, options?.flags || 'g'),\n severity: options?.severity || 'high',\n description: options?.description || `Custom pattern: ${name}`,\n placeholder: options?.placeholder || id.toUpperCase().replace(/-/g, '_'),\n };\n};\n\n/**\n * Binary file extensions that should be skipped during scanning\n */\nexport const BINARY_EXTENSIONS = new Set([\n // Images\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.bmp',\n '.ico',\n '.webp',\n '.svg',\n '.tiff',\n '.tif',\n // Documents\n '.pdf',\n '.doc',\n '.docx',\n '.xls',\n '.xlsx',\n '.ppt',\n '.pptx',\n // Archives\n '.zip',\n '.tar',\n '.gz',\n '.bz2',\n '.7z',\n '.rar',\n '.xz',\n // Binaries\n '.exe',\n '.dll',\n '.so',\n '.dylib',\n '.bin',\n '.o',\n '.a',\n // Fonts\n '.ttf',\n '.otf',\n '.woff',\n '.woff2',\n '.eot',\n // Media\n '.mp3',\n '.mp4',\n '.wav',\n '.avi',\n '.mov',\n '.mkv',\n '.flac',\n // Database\n '.db',\n '.sqlite',\n '.sqlite3',\n // Other\n '.pyc',\n '.pyo',\n '.class',\n '.jar',\n]);\n\n/**\n * Check if a file should be skipped based on extension\n * Note: For files with multiple dots (e.g., archive.tar.gz), only the final extension (.gz) is checked\n */\nexport const shouldSkipFile = (filepath: string): boolean => {\n const lastDotIndex = filepath.lastIndexOf('.');\n if (lastDotIndex === -1 || lastDotIndex === filepath.length - 1) {\n // No extension or dot is at the end\n return false;\n }\n const ext = filepath.slice(lastDotIndex).toLowerCase();\n return BINARY_EXTENSIONS.has(ext);\n};\n","/**\n * Secret scanning engine for tuck\n *\n * Provides functions to scan file content for secrets using pattern matching.\n */\n\nimport { readFile, stat } from 'fs/promises';\nimport { expandPath, collapsePath, pathExists } from '../paths.js';\nimport {\n ALL_SECRET_PATTERNS,\n getPatternsAboveSeverity,\n shouldSkipFile,\n type SecretPattern,\n type SecretSeverity,\n} from './patterns.js';\n\n// Maximum file size to scan (10MB)\nconst MAX_FILE_SIZE = 10 * 1024 * 1024;\n\n// Security: File count limits to prevent resource exhaustion\nconst MAX_FILES_PER_SCAN = 1000; // Hard limit on files per scan\nconst WARN_FILES_THRESHOLD = 100; // Warn user when scanning many files\n\n// Security: Timeout protection to prevent DoS from pathological patterns\nconst SCAN_TIMEOUT_MS = 30000; // 30 seconds max for entire content scan\nconst PATTERN_TIMEOUT_MS = 5000; // 5 seconds max per pattern\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SecretMatch {\n patternId: string;\n patternName: string;\n severity: SecretSeverity;\n value: string;\n redactedValue: string;\n line: number;\n column: number;\n context: string;\n placeholder: string;\n}\n\nexport interface FileScanResult {\n path: string;\n collapsedPath: string;\n hasSecrets: boolean;\n matches: SecretMatch[];\n criticalCount: number;\n highCount: number;\n mediumCount: number;\n lowCount: number;\n skipped: boolean;\n skipReason?: string;\n}\n\nexport interface ScanOptions {\n patterns?: SecretPattern[];\n customPatterns?: SecretPattern[];\n excludePatternIds?: string[];\n minSeverity?: SecretSeverity;\n maxFileSize?: number;\n}\n\nexport interface ScanSummary {\n totalFiles: number;\n scannedFiles: number;\n skippedFiles: number;\n filesWithSecrets: number;\n totalSecrets: number;\n bySeverity: {\n critical: number;\n high: number;\n medium: number;\n low: number;\n };\n results: FileScanResult[];\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Redact a secret value for display\n * Security: NEVER show any actual characters from the secret to prevent information leakage.\n * Only show length indicators and type hints.\n */\nexport const redactSecret = (value: string): string => {\n // For multiline values (like private keys), show type hint only\n if (value.includes('\\n')) {\n const firstLine = value.split('\\n')[0];\n if (firstLine.startsWith('-----BEGIN')) {\n // Show only the header type, no actual content\n return firstLine + '\\n[REDACTED - Private Key]';\n }\n return '[REDACTED MULTILINE SECRET]';\n }\n\n // Security: Never show any actual characters from the secret\n // Only show length indicator to help identify which secret it is\n if (value.length <= 20) {\n return '[REDACTED]';\n } else if (value.length <= 50) {\n return '[REDACTED SECRET]';\n } else {\n return '[REDACTED LONG SECRET]';\n }\n};\n\n/**\n * Get line and column number from string index\n */\nconst getPosition = (content: string, index: number): { line: number; column: number } => {\n const beforeMatch = content.slice(0, index);\n const lines = beforeMatch.split('\\n');\n return {\n line: lines.length,\n column: lines[lines.length - 1].length + 1,\n };\n};\n\n/**\n * Get the line containing the match with secret redacted\n * Security: Ensures the secret is always fully redacted in the context,\n * with fallback to fully redacting the line if replacement fails.\n */\nconst getContext = (content: string, lineNum: number, secretValue: string): string => {\n const lines = content.split('\\n');\n const line = lines[lineNum - 1] || '';\n\n try {\n // Redact the secret in the context\n let contextLine: string;\n const secretToFind = secretValue.includes('\\n') ? secretValue.split('\\n')[0] : secretValue;\n\n // Security: Escape regex special characters in secret value\n const escaped = secretToFind.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regex = new RegExp(escaped, 'g');\n contextLine = line.replace(regex, '[REDACTED]');\n\n // Security: If the replacement didn't change the line but it might contain part of the secret,\n // fully redact the line to prevent any potential leakage\n if (contextLine === line && secretToFind.length > 4) {\n // Check if any significant portion of the secret might be in the line\n const partialSecret = secretToFind.slice(0, Math.min(8, secretToFind.length));\n if (line.includes(partialSecret)) {\n return '[Line contains secret - REDACTED]';\n }\n }\n\n // Truncate long lines\n if (contextLine.length > 100) {\n contextLine = contextLine.slice(0, 97) + '...';\n }\n\n return contextLine.trim();\n } catch {\n // Security: On any error, return fully redacted context\n return '[Context redacted for security]';\n }\n};\n\n/**\n * Clone a regex pattern to reset its lastIndex\n */\nconst clonePattern = (pattern: RegExp): RegExp => {\n return new RegExp(pattern.source, pattern.flags);\n};\n\n// ============================================================================\n// Core Scanning Functions\n// ============================================================================\n\n/**\n * Scan content string for secrets\n */\nexport const scanContent = (content: string, options: ScanOptions = {}): SecretMatch[] => {\n const matches: SecretMatch[] = [];\n const seenMatches = new Set<string>(); // Deduplicate matches\n\n // Security: Track scan start time for timeout protection\n const scanStartTime = Date.now();\n\n // Determine which patterns to use\n let patterns: SecretPattern[];\n\n if (options.patterns) {\n patterns = options.patterns;\n } else if (options.minSeverity) {\n patterns = getPatternsAboveSeverity(options.minSeverity);\n } else {\n patterns = ALL_SECRET_PATTERNS;\n }\n\n // Add custom patterns\n if (options.customPatterns) {\n patterns = [...patterns, ...options.customPatterns];\n }\n\n // Exclude specific pattern IDs\n if (options.excludePatternIds && options.excludePatternIds.length > 0) {\n const excludeSet = new Set(options.excludePatternIds);\n patterns = patterns.filter((p) => !excludeSet.has(p.id));\n }\n\n // Scan with each pattern\n for (const pattern of patterns) {\n // Security: Check total scan timeout\n if (Date.now() - scanStartTime > SCAN_TIMEOUT_MS) {\n console.warn('[tuck] Warning: Scan timeout reached, some patterns may not have been checked');\n break;\n }\n\n // Clone the pattern to reset lastIndex\n const regex = clonePattern(pattern.pattern);\n\n // Security: Track pattern start time\n const patternStartTime = Date.now();\n\n let match: RegExpExecArray | null;\n while ((match = regex.exec(content)) !== null) {\n // Security: Check pattern timeout to prevent ReDoS\n if (Date.now() - patternStartTime > PATTERN_TIMEOUT_MS) {\n console.warn(`[tuck] Warning: Pattern ${pattern.id} timed out, skipping remaining matches`);\n break;\n }\n\n // Extract the captured value (prefer capture group 1 if exists)\n const value = match[1] || match[0];\n\n // Skip empty or very short matches\n if (!value || value.length < 4) {\n continue;\n }\n\n // Create unique key for deduplication\n const matchKey = `${pattern.id}:${match.index}:${value.length}`;\n if (seenMatches.has(matchKey)) {\n continue;\n }\n seenMatches.add(matchKey);\n\n const position = getPosition(content, match.index);\n\n matches.push({\n patternId: pattern.id,\n patternName: pattern.name,\n severity: pattern.severity,\n value,\n redactedValue: redactSecret(value),\n line: position.line,\n column: position.column,\n context: getContext(content, position.line, value),\n placeholder: pattern.placeholder,\n });\n\n // Prevent infinite loops for zero-width matches\n if (match.index === regex.lastIndex) {\n regex.lastIndex++;\n }\n }\n }\n\n // Sort by line number, then column\n matches.sort((a, b) => {\n if (a.line !== b.line) return a.line - b.line;\n return a.column - b.column;\n });\n\n return matches;\n};\n\n/**\n * Scan a single file for secrets\n */\nexport const scanFile = async (filepath: string, options: ScanOptions = {}): Promise<FileScanResult> => {\n const expandedPath = expandPath(filepath);\n const collapsedPath = collapsePath(expandedPath);\n const maxSize = options.maxFileSize || MAX_FILE_SIZE;\n\n // Check if file exists\n if (!(await pathExists(expandedPath))) {\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: 'File not found',\n };\n }\n\n // Check if it's a binary file by extension\n if (shouldSkipFile(expandedPath)) {\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: 'Binary file',\n };\n }\n\n // Check file size\n try {\n const stats = await stat(expandedPath);\n if (stats.size > maxSize) {\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: `File too large (${Math.round(stats.size / 1024 / 1024)}MB > ${Math.round(maxSize / 1024 / 1024)}MB)`,\n };\n }\n\n // Skip directories\n if (stats.isDirectory()) {\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: 'Is a directory',\n };\n }\n } catch {\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: 'Cannot read file stats',\n };\n }\n\n // Read and scan file content\n try {\n const content = await readFile(expandedPath, 'utf-8');\n const matches = scanContent(content, options);\n\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: matches.length > 0,\n matches,\n criticalCount: matches.filter((m) => m.severity === 'critical').length,\n highCount: matches.filter((m) => m.severity === 'high').length,\n mediumCount: matches.filter((m) => m.severity === 'medium').length,\n lowCount: matches.filter((m) => m.severity === 'low').length,\n skipped: false,\n };\n } catch (error) {\n // Handle encoding errors (likely binary content)\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: 'Cannot read file (possibly binary)',\n };\n }\n};\n\n/**\n * Scan multiple files for secrets\n */\nexport const scanFiles = async (filepaths: string[], options: ScanOptions = {}): Promise<ScanSummary> => {\n // Security: Check file count limits to prevent resource exhaustion\n if (filepaths.length > MAX_FILES_PER_SCAN) {\n throw new Error(\n `Too many files to scan (${filepaths.length} > ${MAX_FILES_PER_SCAN}). ` +\n 'Please scan in smaller batches or use --exclude patterns to reduce scan scope.'\n );\n }\n\n if (filepaths.length > WARN_FILES_THRESHOLD) {\n console.warn(\n `[tuck] Warning: Scanning ${filepaths.length} files may take a while. ` +\n 'Consider using --exclude patterns to reduce scan scope if this is slow.'\n );\n }\n\n const results: FileScanResult[] = [];\n\n // Scan files in parallel batches (with concurrency limit)\n const CONCURRENCY = 10;\n for (let i = 0; i < filepaths.length; i += CONCURRENCY) {\n const batch = filepaths.slice(i, i + CONCURRENCY);\n const batchResults = await Promise.all(batch.map((path) => scanFile(path, options)));\n results.push(...batchResults);\n }\n\n // Build summary\n const summary: ScanSummary = {\n totalFiles: filepaths.length,\n scannedFiles: results.filter((r) => !r.skipped).length,\n skippedFiles: results.filter((r) => r.skipped).length,\n filesWithSecrets: results.filter((r) => r.hasSecrets).length,\n totalSecrets: 0,\n bySeverity: { critical: 0, high: 0, medium: 0, low: 0 },\n results: results.filter((r) => r.hasSecrets), // Only include files with secrets\n };\n\n for (const result of results) {\n summary.totalSecrets += result.matches.length;\n summary.bySeverity.critical += result.criticalCount;\n summary.bySeverity.high += result.highCount;\n summary.bySeverity.medium += result.mediumCount;\n summary.bySeverity.low += result.lowCount;\n }\n\n return summary;\n};\n\n/**\n * Generate unique placeholder names when there are duplicates\n */\nexport const generateUniquePlaceholder = (\n basePlaceholder: string,\n existingPlaceholders: Set<string>,\n hint?: string\n): string => {\n let placeholder = basePlaceholder;\n\n // Add hint to make it more descriptive\n if (hint) {\n const sanitizedHint = hint.toUpperCase().replace(/[^A-Z0-9]/g, '_');\n placeholder = `${basePlaceholder}_${sanitizedHint}`;\n }\n\n // Ensure uniqueness\n if (!existingPlaceholders.has(placeholder)) {\n existingPlaceholders.add(placeholder);\n return placeholder;\n }\n\n // Add numeric suffix\n let counter = 1;\n while (existingPlaceholders.has(`${placeholder}_${counter}`)) {\n counter++;\n }\n\n const uniquePlaceholder = `${placeholder}_${counter}`;\n existingPlaceholders.add(uniquePlaceholder);\n return uniquePlaceholder;\n};\n\n/**\n * Get all unique secret values from scan results with their placeholders\n */\nexport const getSecretsWithPlaceholders = (\n results: FileScanResult[]\n): Map<string, { placeholder: string; pattern: string; severity: SecretSeverity }> => {\n const secrets = new Map<string, { placeholder: string; pattern: string; severity: SecretSeverity }>();\n const usedPlaceholders = new Set<string>();\n\n for (const result of results) {\n for (const match of result.matches) {\n // Skip if we already have this exact secret value\n if (secrets.has(match.value)) {\n continue;\n }\n\n // Generate unique placeholder\n const placeholder = generateUniquePlaceholder(match.placeholder, usedPlaceholders);\n\n secrets.set(match.value, {\n placeholder,\n pattern: match.patternName,\n severity: match.severity,\n });\n }\n }\n\n return secrets;\n};\n","/**\n * Local secrets store management for tuck\n *\n * Manages the secrets.local.json file which stores actual secret values\n * locally (never committed to git). These values are used to replace\n * placeholders in dotfiles.\n */\n\nimport { readFile, writeFile, chmod, stat } from 'fs/promises';\nimport { join } from 'path';\nimport { ensureDir } from 'fs-extra';\nimport { pathExists } from '../paths.js';\nimport { secretsStoreSchema, type SecretsStore } from '../../schemas/secrets.schema.js';\n\n// File permission constants\nconst SECRETS_FILE_MODE = 0o600; // Owner read/write only (rw-------)\nconst TUCK_DIR_MODE = 0o700; // Owner read/write/execute only (rwx------)\n\nconst SECRETS_FILENAME = 'secrets.local.json';\n\n// ============================================================================\n// Path Helpers\n// ============================================================================\n\n/**\n * Get the path to the secrets file\n */\nexport const getSecretsPath = (tuckDir: string): string => {\n return join(tuckDir, SECRETS_FILENAME);\n};\n\n// ============================================================================\n// Store Operations\n// ============================================================================\n\n/**\n * Load the secrets store from disk\n */\nexport const loadSecretsStore = async (tuckDir: string): Promise<SecretsStore> => {\n const secretsPath = getSecretsPath(tuckDir);\n\n if (!(await pathExists(secretsPath))) {\n return {\n version: '1.0.0',\n secrets: {},\n };\n }\n\n // Security: Check and fix file permissions if too permissive\n try {\n const stats = await stat(secretsPath);\n const mode = stats.mode & 0o777;\n // If group or other have any permissions, fix it\n if ((mode & 0o077) !== 0) {\n await chmod(secretsPath, SECRETS_FILE_MODE);\n }\n } catch {\n // Ignore permission check errors (might be Windows)\n }\n\n try {\n const content = await readFile(secretsPath, 'utf-8');\n const parsed = JSON.parse(content);\n return secretsStoreSchema.parse(parsed);\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n\n // If the file disappeared between the existence check and read, treat as \"no secrets yet\"\n if (typeof error === 'object' && error !== null && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n console.warn(\n `[tuck] Warning: Secrets store file not found when reading at '${secretsPath}': ${errorMsg}`\n );\n return {\n version: '1.0.0',\n secrets: {},\n };\n }\n\n // For any other error (permissions, corruption, validation issues), surface a clear failure\n console.error(\n `[tuck] Error: Failed to load secrets store from '${secretsPath}': ${errorMsg}`\n );\n throw new Error(\n `[tuck] Failed to load secrets store from '${secretsPath}': ${errorMsg}`\n );\n }\n};\n\n// Track if we've warned about Windows permissions (only warn once per session)\nlet windowsPermissionWarningShown = false;\n\n/**\n * Save the secrets store to disk with secure permissions\n */\nexport const saveSecretsStore = async (tuckDir: string, store: SecretsStore): Promise<void> => {\n const secretsPath = getSecretsPath(tuckDir);\n await ensureDir(tuckDir);\n\n // Security: Set directory permissions to owner-only\n try {\n await chmod(tuckDir, TUCK_DIR_MODE);\n } catch {\n // chmod not supported (Windows) - permissions handled differently\n }\n\n const content = JSON.stringify(store, null, 2) + '\\n';\n await writeFile(secretsPath, content, 'utf-8');\n\n // Security: Set file permissions to owner read/write only (0600)\n try {\n await chmod(secretsPath, SECRETS_FILE_MODE);\n } catch {\n // Security: Warn Windows users about permission limitations (once per session)\n if (process.platform === 'win32' && !windowsPermissionWarningShown) {\n console.warn(\n '[tuck] Warning: On Windows, file permissions cannot be restricted to owner-only. ' +\n 'Ensure your secrets file is in a secure location not accessible to other users.'\n );\n windowsPermissionWarningShown = true;\n }\n }\n};\n\n// ============================================================================\n// Secret CRUD Operations\n// ============================================================================\n\n/**\n * Set (add or update) a secret\n */\nexport const setSecret = async (\n tuckDir: string,\n name: string,\n value: string,\n options?: {\n description?: string;\n source?: string;\n }\n): Promise<void> => {\n const store = await loadSecretsStore(tuckDir);\n const now = new Date().toISOString();\n\n store.secrets[name] = {\n value,\n placeholder: `{{${name}}}`,\n description: options?.description,\n source: options?.source,\n addedAt: store.secrets[name]?.addedAt || now,\n lastUsed: now,\n };\n\n await saveSecretsStore(tuckDir, store);\n};\n\n/**\n * Get a secret value by name\n */\nexport const getSecret = async (tuckDir: string, name: string): Promise<string | undefined> => {\n const store = await loadSecretsStore(tuckDir);\n return store.secrets[name]?.value;\n};\n\n/**\n * Remove a secret by name\n */\nexport const unsetSecret = async (tuckDir: string, name: string): Promise<boolean> => {\n const store = await loadSecretsStore(tuckDir);\n\n if (name in store.secrets) {\n delete store.secrets[name];\n await saveSecretsStore(tuckDir, store);\n return true;\n }\n\n return false;\n};\n\n/**\n * Check if a secret exists\n */\nexport const hasSecret = async (tuckDir: string, name: string): Promise<boolean> => {\n const store = await loadSecretsStore(tuckDir);\n return name in store.secrets;\n};\n\n// ============================================================================\n// Listing and Querying\n// ============================================================================\n\n/**\n * List all secrets (without values, for display)\n */\nexport const listSecrets = async (\n tuckDir: string\n): Promise<\n Array<{\n name: string;\n placeholder: string;\n description?: string;\n source?: string;\n addedAt: string;\n lastUsed?: string;\n }>\n> => {\n const store = await loadSecretsStore(tuckDir);\n\n return Object.entries(store.secrets).map(([name, entry]) => ({\n name,\n placeholder: entry.placeholder,\n description: entry.description,\n source: entry.source,\n addedAt: entry.addedAt,\n lastUsed: entry.lastUsed,\n }));\n};\n\n/**\n * Get all secrets as a name->value map (for restoration)\n */\nexport const getAllSecrets = async (tuckDir: string): Promise<Record<string, string>> => {\n const store = await loadSecretsStore(tuckDir);\n\n const result: Record<string, string> = {};\n for (const [name, entry] of Object.entries(store.secrets)) {\n result[name] = entry.value;\n }\n\n return result;\n};\n\n/**\n * Get secret count\n */\nexport const getSecretCount = async (tuckDir: string): Promise<number> => {\n const store = await loadSecretsStore(tuckDir);\n return Object.keys(store.secrets).length;\n};\n\n// ============================================================================\n// Bulk Operations\n// ============================================================================\n\n/**\n * Add multiple secrets at once\n */\nexport const setSecrets = async (\n tuckDir: string,\n secrets: Array<{\n name: string;\n value: string;\n description?: string;\n source?: string;\n }>\n): Promise<void> => {\n const store = await loadSecretsStore(tuckDir);\n const now = new Date().toISOString();\n\n for (const secret of secrets) {\n store.secrets[secret.name] = {\n value: secret.value,\n placeholder: `{{${secret.name}}}`,\n description: secret.description,\n source: secret.source,\n addedAt: store.secrets[secret.name]?.addedAt || now,\n lastUsed: now,\n };\n }\n\n await saveSecretsStore(tuckDir, store);\n};\n\n/**\n * Update lastUsed timestamp for secrets that were used\n */\nexport const touchSecrets = async (tuckDir: string, names: string[]): Promise<void> => {\n const store = await loadSecretsStore(tuckDir);\n const now = new Date().toISOString();\n\n let changed = false;\n for (const name of names) {\n if (name in store.secrets) {\n store.secrets[name].lastUsed = now;\n changed = true;\n }\n }\n\n if (changed) {\n await saveSecretsStore(tuckDir, store);\n }\n};\n\n// ============================================================================\n// Git Integration\n// ============================================================================\n\n/**\n * Ensure the secrets file is in .gitignore\n */\nexport const ensureSecretsGitignored = async (tuckDir: string): Promise<void> => {\n const gitignorePath = join(tuckDir, '.gitignore');\n\n let gitignoreContent = '';\n if (await pathExists(gitignorePath)) {\n gitignoreContent = await readFile(gitignorePath, 'utf-8');\n }\n\n // Check if already ignored\n if (gitignoreContent.includes(SECRETS_FILENAME)) {\n return;\n }\n\n // Add to .gitignore\n const newContent = gitignoreContent.trim()\n ? `${gitignoreContent.trim()}\\n\\n# Local secrets (NEVER commit)\\n${SECRETS_FILENAME}\\n`\n : `# Local secrets (NEVER commit)\\n${SECRETS_FILENAME}\\n`;\n\n await writeFile(gitignorePath, newContent, 'utf-8');\n};\n\n// ============================================================================\n// Validation\n// ============================================================================\n\n// Security: Maximum secret name length to prevent file system issues and abuse\nconst MAX_SECRET_NAME_LENGTH = 100;\nconst MIN_SECRET_NAME_LENGTH = 1;\n\n/**\n * Validate secret name format and length\n */\nexport const isValidSecretName = (name: string): boolean => {\n // Check length bounds\n if (name.length < MIN_SECRET_NAME_LENGTH || name.length > MAX_SECRET_NAME_LENGTH) {\n return false;\n }\n // Must be uppercase alphanumeric with underscores, starting with an uppercase letter (A-Z)\n return /^[A-Z][A-Z0-9_]*$/.test(name);\n};\n\n/**\n * Normalize a secret name to valid format\n * Security: Enforces length limits and validates result is not empty\n */\nexport const normalizeSecretName = (name: string): string => {\n let normalized = name\n .toUpperCase()\n .replace(/[^A-Z0-9_]/g, '_')\n .replace(/^[0-9_]+/, '') // Remove leading numbers and underscores\n .replace(/_+/g, '_') // Collapse multiple underscores\n .replace(/^_|_$/g, ''); // Trim leading/trailing underscores\n\n // Security: If normalization resulted in empty string, use a fallback\n if (normalized.length === 0) {\n normalized = 'SECRET';\n }\n\n // Security: Truncate to max length\n if (normalized.length > MAX_SECRET_NAME_LENGTH) {\n normalized = normalized.slice(0, MAX_SECRET_NAME_LENGTH);\n }\n\n // Ensure it starts with a letter (add prefix if needed)\n if (!/^[A-Z]/.test(normalized)) {\n normalized = 'S_' + normalized;\n if (normalized.length > MAX_SECRET_NAME_LENGTH) {\n normalized = normalized.slice(0, MAX_SECRET_NAME_LENGTH);\n }\n }\n\n return normalized;\n};\n","/**\n * Secret redaction and restoration for tuck\n *\n * Handles replacing secrets with placeholders in file content,\n * and restoring them from the local secrets store.\n */\n\nimport { readFile, writeFile, rename, unlink, stat } from 'fs/promises';\nimport { randomBytes } from 'crypto';\nimport { dirname, basename, join } from 'path';\nimport { expandPath, pathExists } from '../paths.js';\nimport type { SecretMatch } from './scanner.js';\nimport { getAllSecrets } from './store.js';\n\n// ============================================================================\n// Atomic File Operations\n// ============================================================================\n\n/**\n * Atomically write to a file by writing to a temp file first, then renaming.\n * This prevents data loss from race conditions or crashes during write.\n */\nconst atomicWriteFile = async (filepath: string, content: string): Promise<void> => {\n // Generate unique temp filename in same directory (for same-filesystem rename)\n const tempSuffix = randomBytes(8).toString('hex');\n const tempPath = join(dirname(filepath), `.${basename(filepath)}.tmp.${tempSuffix}`);\n\n try {\n // Get original file permissions if file exists\n let mode: number | undefined;\n let fileExists = false;\n try {\n const stats = await stat(filepath);\n mode = stats.mode;\n fileExists = true;\n } catch {\n // File doesn't exist\n }\n\n // Security: For new security-sensitive files (e.g., dotfiles), use restrictive permissions\n if (!fileExists && basename(filepath).startsWith('.')) {\n mode = 0o600; // Owner read/write only\n }\n\n // Write to temp file first\n await writeFile(tempPath, content, { encoding: 'utf-8', mode });\n\n // Atomically rename temp to target (this is atomic on POSIX systems)\n await rename(tempPath, filepath);\n } catch (error) {\n // Clean up temp file on error\n try {\n await unlink(tempPath);\n } catch {\n // Ignore cleanup errors\n }\n throw error;\n }\n};\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RedactionResult {\n originalContent: string;\n redactedContent: string;\n replacements: Array<{\n placeholder: string;\n originalValue: string;\n line: number;\n }>;\n}\n\nexport interface RestorationResult {\n originalContent: string;\n restoredContent: string;\n restored: number;\n unresolved: string[];\n}\n\n// ============================================================================\n// Placeholder Formatting\n// ============================================================================\n\n/**\n * Format a placeholder name into placeholder syntax\n */\nexport const formatPlaceholder = (name: string): string => {\n return `{{${name}}}`;\n};\n\n/**\n * Extract placeholder name from placeholder syntax\n */\nexport const parsePlaceholder = (placeholder: string): string | null => {\n const match = placeholder.match(/^\\{\\{([A-Z][A-Z0-9_]*)\\}\\}$/);\n return match ? match[1] : null;\n};\n\n/**\n * Regex to find all placeholders in content\n */\nexport const PLACEHOLDER_REGEX = /\\{\\{([A-Z][A-Z0-9_]*)\\}\\}/g;\n\n// ============================================================================\n// Content Redaction\n// ============================================================================\n\n/**\n * Redact secrets in content string with placeholders\n */\nexport const redactContent = (\n content: string,\n matches: SecretMatch[],\n placeholderMap: Map<string, string> // secret value -> placeholder name\n): RedactionResult => {\n let redactedContent = content;\n const replacements: RedactionResult['replacements'] = [];\n\n // Process all matches and replace secret values with placeholders\n // Note: The split/join approach processes content multiple times, which could be\n // optimized for large files by processing matches in reverse order by position.\n // However, this approach is simpler and works well for typical config files.\n for (const match of matches) {\n const placeholderName = placeholderMap.get(match.value) || match.placeholder;\n const placeholder = formatPlaceholder(placeholderName);\n\n // Replace all occurrences of this secret value\n // Use a temporary marker to avoid replacing already-replaced content\n // Security: Use crypto.randomBytes for unpredictable temp markers\n const tempMarker = `__TUCK_TEMP_${randomBytes(16).toString('hex')}__`;\n redactedContent = redactedContent.split(match.value).join(tempMarker);\n redactedContent = redactedContent.split(tempMarker).join(placeholder);\n\n replacements.push({\n placeholder: placeholderName,\n originalValue: match.value,\n line: match.line,\n });\n }\n\n return {\n originalContent: content,\n redactedContent,\n replacements: replacements.reverse(), // Return in reverse line order (last line first) so callers can safely apply replacements without affecting subsequent line positions\n };\n};\n\n/**\n * Redact a file in place, returning the mapping for storage\n */\nexport const redactFile = async (\n filepath: string,\n matches: SecretMatch[],\n placeholderMap: Map<string, string>\n): Promise<RedactionResult> => {\n const expandedPath = expandPath(filepath);\n const content = await readFile(expandedPath, 'utf-8');\n\n const result = redactContent(content, matches, placeholderMap);\n\n // Security: Use atomic write to prevent data loss from race conditions\n await atomicWriteFile(expandedPath, result.redactedContent);\n\n return result;\n};\n\n// ============================================================================\n// Content Restoration\n// ============================================================================\n\n/**\n * Restore secrets in content string from placeholders\n */\nexport const restoreContent = (\n content: string,\n secrets: Record<string, string> // placeholder name -> actual value\n): RestorationResult => {\n let restoredContent = content;\n let restored = 0;\n const unresolved: string[] = [];\n const seenUnresolved = new Set<string>();\n\n // Find all placeholders in the content\n const matches = [...content.matchAll(PLACEHOLDER_REGEX)];\n\n for (const match of matches) {\n const placeholderName = match[1];\n const fullPlaceholder = match[0];\n\n if (placeholderName in secrets) {\n // Replace this placeholder with actual value\n restoredContent = restoredContent.replaceAll(fullPlaceholder, secrets[placeholderName]);\n restored++;\n } else if (!seenUnresolved.has(placeholderName)) {\n // Track unresolved placeholders\n unresolved.push(placeholderName);\n seenUnresolved.add(placeholderName);\n }\n }\n\n return {\n originalContent: content,\n restoredContent,\n restored,\n unresolved,\n };\n};\n\n/**\n * Restore a file in place from the secrets store\n */\nexport const restoreFile = async (\n filepath: string,\n tuckDir: string\n): Promise<{ restored: number; unresolved: string[] }> => {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n return { restored: 0, unresolved: [] };\n }\n\n const content = await readFile(expandedPath, 'utf-8');\n const secrets = await getAllSecrets(tuckDir);\n\n const result = restoreContent(content, secrets);\n\n // Only write if changes were made\n if (result.restored > 0) {\n // Security: Use atomic write to prevent data loss from race conditions\n await atomicWriteFile(expandedPath, result.restoredContent);\n }\n\n return {\n restored: result.restored,\n unresolved: result.unresolved,\n };\n};\n\n// ============================================================================\n// Placeholder Detection\n// ============================================================================\n\n/**\n * Find all placeholders in content\n */\nexport const findPlaceholders = (content: string): string[] => {\n const placeholders: string[] = [];\n const matches = content.matchAll(PLACEHOLDER_REGEX);\n\n for (const match of matches) {\n if (!placeholders.includes(match[1])) {\n placeholders.push(match[1]);\n }\n }\n\n return placeholders;\n};\n\n/**\n * Find unresolved placeholders in content (those without stored values)\n */\nexport const findUnresolvedPlaceholders = (\n content: string,\n availableSecrets: Record<string, string>\n): string[] => {\n const placeholders = findPlaceholders(content);\n return placeholders.filter((name) => !(name in availableSecrets));\n};\n\n/**\n * Check if content has any placeholders\n */\nexport const hasPlaceholders = (content: string): boolean => {\n // Use a cloned regex instance to avoid shared lastIndex state issues\n const regex = new RegExp(PLACEHOLDER_REGEX.source, PLACEHOLDER_REGEX.flags);\n return regex.test(content);\n};\n\n/**\n * Count placeholders in content\n */\nexport const countPlaceholders = (content: string): number => {\n const matches = content.match(PLACEHOLDER_REGEX);\n return matches ? matches.length : 0;\n};\n\n// ============================================================================\n// Batch Operations\n// ============================================================================\n\n/**\n * Restore multiple files in place\n */\nexport const restoreFiles = async (\n filepaths: string[],\n tuckDir: string\n): Promise<{\n totalRestored: number;\n filesModified: number;\n allUnresolved: string[];\n}> => {\n const secrets = await getAllSecrets(tuckDir);\n let totalRestored = 0;\n let filesModified = 0;\n const allUnresolved = new Set<string>();\n\n for (const filepath of filepaths) {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n continue;\n }\n\n const content = await readFile(expandedPath, 'utf-8');\n const result = restoreContent(content, secrets);\n\n if (result.restored > 0) {\n // Security: Use atomic write to prevent data loss from race conditions\n await atomicWriteFile(expandedPath, result.restoredContent);\n totalRestored += result.restored;\n filesModified++;\n }\n\n for (const unresolved of result.unresolved) {\n allUnresolved.add(unresolved);\n }\n }\n\n return {\n totalRestored,\n filesModified,\n allUnresolved: [...allUnresolved],\n };\n};\n\n/**\n * Preview what placeholders would be restored without modifying files\n */\nexport const previewRestoration = async (\n filepath: string,\n tuckDir: string\n): Promise<{\n wouldRestore: number;\n unresolved: string[];\n placeholders: string[];\n}> => {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n return { wouldRestore: 0, unresolved: [], placeholders: [] };\n }\n\n const content = await readFile(expandedPath, 'utf-8');\n const secrets = await getAllSecrets(tuckDir);\n const placeholders = findPlaceholders(content);\n\n const resolved = placeholders.filter((p) => p in secrets);\n const unresolved = placeholders.filter((p) => !(p in secrets));\n\n return {\n wouldRestore: resolved.length,\n unresolved,\n placeholders,\n };\n};\n","/**\n * External secret scanner integration\n *\n * Provides optional integration with external tools like gitleaks and trufflehog.\n * Falls back to built-in scanning if external tools are not available.\n */\n\n// Security: Use execFile instead of exec to prevent command injection\n// execFile doesn't use shell interpolation, so malicious filenames can't execute arbitrary commands\nimport { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport { z } from 'zod';\nimport type { SecretMatch, FileScanResult, ScanSummary } from './scanner.js';\nimport { scanFiles as builtinScanFiles, redactSecret } from './scanner.js';\nimport type { SecretSeverity } from './patterns.js';\nimport { collapsePath } from '../paths.js';\n\nconst execFileAsync = promisify(execFile);\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ExternalScanner = 'gitleaks' | 'trufflehog' | 'builtin';\n\n// Security: Zod schema for validating gitleaks JSON output\n// This prevents prototype pollution and ensures type safety from external tool output\nconst gitleaksResultSchema = z.object({\n Description: z.string(),\n StartLine: z.number(),\n EndLine: z.number(),\n StartColumn: z.number(),\n EndColumn: z.number(),\n Match: z.string(),\n Secret: z.string(),\n File: z.string(),\n SymlinkFile: z.string().optional().default(''),\n Commit: z.string().optional().default(''),\n Entropy: z.number().optional().default(0),\n Author: z.string().optional().default(''),\n Email: z.string().optional().default(''),\n Date: z.string().optional().default(''),\n Message: z.string().optional().default(''),\n Tags: z.array(z.string()).optional().default([]),\n RuleID: z.string(),\n Fingerprint: z.string().optional().default(''),\n});\n\nconst gitleaksOutputSchema = z.array(gitleaksResultSchema);\n\ntype GitleaksResult = z.infer<typeof gitleaksResultSchema>;\n\n// ============================================================================\n// Scanner Detection\n// ============================================================================\n\n/**\n * Check if gitleaks is installed\n */\nexport const isGitleaksInstalled = async (): Promise<boolean> => {\n try {\n // Security: Use execFileAsync to prevent command injection\n await execFileAsync('gitleaks', ['version']);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Check if trufflehog is installed\n */\nexport const isTrufflehogInstalled = async (): Promise<boolean> => {\n try {\n // Security: Use execFileAsync to prevent command injection\n await execFileAsync('trufflehog', ['--version']);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Get available scanners\n */\nexport const getAvailableScanners = async (): Promise<ExternalScanner[]> => {\n const available: ExternalScanner[] = ['builtin'];\n\n if (await isGitleaksInstalled()) {\n available.push('gitleaks');\n }\n\n if (await isTrufflehogInstalled()) {\n available.push('trufflehog');\n }\n\n return available;\n};\n\n// ============================================================================\n// Gitleaks Integration\n// ============================================================================\n\n/**\n * Map gitleaks severity/rule to our severity levels\n */\nconst mapGitleaksSeverity = (ruleId: string): SecretSeverity => {\n // Critical patterns\n const criticalPatterns = [\n 'aws', 'gcp', 'azure', 'private-key', 'stripe', 'github',\n 'gitlab', 'npm', 'pypi', 'jwt', 'oauth',\n ];\n\n // High severity patterns\n const highPatterns = [\n 'api', 'token', 'secret', 'password', 'credential',\n ];\n\n const ruleIdLower = ruleId.toLowerCase();\n\n if (criticalPatterns.some(p => ruleIdLower.includes(p))) {\n return 'critical';\n }\n\n if (highPatterns.some(p => ruleIdLower.includes(p))) {\n return 'high';\n }\n\n return 'medium';\n};\n\n/**\n * Generate a placeholder name from gitleaks rule\n */\nconst generatePlaceholderFromRule = (ruleId: string): string => {\n return ruleId\n .toUpperCase()\n .replace(/-/g, '_')\n .replace(/[^A-Z0-9_]/g, '');\n};\n\n/**\n * Scan files using gitleaks\n */\nexport const scanWithGitleaks = async (filepaths: string[]): Promise<ScanSummary> => {\n const results: FileScanResult[] = [];\n let totalSecrets = 0;\n let filesWithSecrets = 0;\n const bySeverity = { critical: 0, high: 0, medium: 0, low: 0 };\n\n // Run gitleaks on files in parallel batches (with concurrency limit)\n const CONCURRENCY = 5; // Lower concurrency for external process spawning\n\n for (let i = 0; i < filepaths.length; i += CONCURRENCY) {\n const batch = filepaths.slice(i, i + CONCURRENCY);\n const batchResults = await Promise.all(\n batch.map(async (filepath): Promise<FileScanResult | null> => {\n try {\n // Security: Use execFileAsync with array arguments to prevent command injection\n // This prevents malicious filenames from executing arbitrary shell commands\n const { stdout, stderr } = await execFileAsync('gitleaks', [\n 'detect',\n '--source', filepath,\n '--no-git',\n '--report-format', 'json',\n '--exit-code', '0'\n ], { maxBuffer: 10 * 1024 * 1024 });\n\n // Check stderr for gitleaks errors (not just secret findings)\n if (stderr && stderr.trim()) {\n // Log stderr but continue - gitleaks may output warnings/errors to stderr\n console.warn(`[tuck] Gitleaks stderr for ${filepath}: ${stderr.trim()}`);\n }\n\n if (!stdout.trim()) return null;\n\n // Security: Use Zod to validate external JSON input\n // This prevents prototype pollution and ensures type safety\n let gitleaksResults: GitleaksResult[];\n try {\n const rawData = JSON.parse(stdout);\n const validated = gitleaksOutputSchema.safeParse(rawData);\n\n if (!validated.success) {\n console.warn(`[tuck] Warning: Invalid gitleaks output format for ${filepath}: ${validated.error.message}`);\n return null;\n }\n\n gitleaksResults = validated.data;\n } catch (parseError) {\n // Log parse error for debugging instead of silent failure\n console.warn(`[tuck] Warning: Failed to parse gitleaks JSON for ${filepath}`);\n return null;\n }\n\n if (gitleaksResults.length === 0) return null;\n\n const matches: SecretMatch[] = [];\n\n for (const finding of gitleaksResults) {\n const severity = mapGitleaksSeverity(finding.RuleID);\n\n // Security: Use consistent redactSecret function for better security\n const secretValue = finding.Secret || finding.Match;\n const redactedValue = redactSecret(secretValue);\n\n matches.push({\n patternId: `gitleaks-${finding.RuleID}`,\n patternName: finding.Description || finding.RuleID,\n severity,\n line: finding.StartLine,\n column: finding.StartColumn,\n value: secretValue,\n redactedValue,\n context: finding.Match,\n placeholder: generatePlaceholderFromRule(finding.RuleID),\n });\n }\n\n // Collapse home directory in path for display using utility function\n const collapsedPath = collapsePath(filepath);\n\n return {\n path: filepath,\n collapsedPath,\n hasSecrets: true,\n matches,\n criticalCount: matches.filter(m => m.severity === 'critical').length,\n highCount: matches.filter(m => m.severity === 'high').length,\n mediumCount: matches.filter(m => m.severity === 'medium').length,\n lowCount: matches.filter(m => m.severity === 'low').length,\n skipped: false,\n };\n } catch (execError) {\n // Log error for debugging instead of silent failure\n const errorMsg = execError instanceof Error ? execError.message : String(execError);\n console.warn(`[tuck] Warning: Gitleaks scan failed for ${filepath}: ${errorMsg}`);\n return null;\n }\n })\n );\n\n // Process batch results\n for (const result of batchResults) {\n if (result) {\n results.push(result);\n filesWithSecrets++;\n totalSecrets += result.matches.length;\n for (const match of result.matches) {\n bySeverity[match.severity]++;\n }\n }\n }\n }\n\n return {\n results,\n totalFiles: filepaths.length,\n scannedFiles: filepaths.length,\n skippedFiles: 0,\n filesWithSecrets,\n totalSecrets,\n bySeverity,\n };\n};\n\n// ============================================================================\n// Scanner Factory\n// ============================================================================\n\n/**\n * Scan files using the specified scanner (or fallback to builtin)\n */\nexport const scanWithScanner = async (\n filepaths: string[],\n scanner: ExternalScanner = 'builtin'\n): Promise<ScanSummary> => {\n if (scanner === 'gitleaks') {\n const isInstalled = await isGitleaksInstalled();\n if (isInstalled) {\n return scanWithGitleaks(filepaths);\n }\n // Fall back to builtin if gitleaks not available\n console.warn('gitleaks not found, falling back to built-in scanner');\n }\n\n if (scanner === 'trufflehog') {\n // Trufflehog integration could be added here\n // For now, fall back to builtin\n console.warn('trufflehog integration not yet implemented, using built-in scanner');\n }\n\n // Use built-in scanner\n return builtinScanFiles(filepaths);\n};\n","/**\n * Secret scanning and management for tuck\n *\n * This module provides comprehensive secret detection, redaction,\n * and management capabilities for dotfiles.\n */\n\n// Re-export pattern types and helpers\nexport {\n type SecretPattern,\n type SecretSeverity,\n ALL_SECRET_PATTERNS,\n CLOUD_PROVIDER_PATTERNS,\n API_TOKEN_PATTERNS,\n PRIVATE_KEY_PATTERNS,\n GENERIC_PATTERNS,\n getPatternById,\n getPatternsBySeverity,\n getPatternsAboveSeverity,\n createCustomPattern,\n shouldSkipFile,\n BINARY_EXTENSIONS,\n} from './patterns.js';\n\n// Re-export scanner types and functions\nexport {\n type SecretMatch,\n type FileScanResult,\n type ScanOptions,\n type ScanSummary,\n scanContent,\n scanFile,\n scanFiles,\n generateUniquePlaceholder,\n getSecretsWithPlaceholders,\n} from './scanner.js';\n\n// Re-export store types and functions\nexport {\n getSecretsPath,\n loadSecretsStore,\n saveSecretsStore,\n setSecret,\n getSecret,\n unsetSecret,\n hasSecret,\n listSecrets,\n getAllSecrets,\n getSecretCount,\n setSecrets,\n touchSecrets,\n ensureSecretsGitignored,\n isValidSecretName,\n normalizeSecretName,\n} from './store.js';\n\n// Re-export redactor types and functions\nexport {\n type RedactionResult,\n type RestorationResult,\n formatPlaceholder,\n parsePlaceholder,\n PLACEHOLDER_REGEX,\n redactContent,\n redactFile,\n restoreContent,\n restoreFile,\n findPlaceholders,\n findUnresolvedPlaceholders,\n hasPlaceholders,\n countPlaceholders,\n restoreFiles,\n previewRestoration,\n} from './redactor.js';\n\n// Re-export schema types\nexport type { SecurityConfig, CustomPattern, SecretEntry, SecretsStore } from '../../schemas/secrets.schema.js';\n\n// Re-export external scanner types and functions\nexport {\n type ExternalScanner,\n isGitleaksInstalled,\n isTrufflehogInstalled,\n getAvailableScanners,\n scanWithGitleaks,\n scanWithScanner,\n} from './external.js';\n\n// ============================================================================\n// High-Level Convenience Functions\n// ============================================================================\n\nimport { loadConfig } from '../config.js';\nimport { scanFiles, type ScanSummary, type FileScanResult } from './scanner.js';\nimport { setSecret, ensureSecretsGitignored } from './store.js';\nimport { createCustomPattern, type SecretPattern } from './patterns.js';\nimport type { CustomPattern } from '../../schemas/secrets.schema.js';\nimport { scanWithScanner, isGitleaksInstalled, isTrufflehogInstalled, type ExternalScanner } from './external.js';\n\n/**\n * Scan files for secrets using config-aware settings\n *\n * Supports external scanners (gitleaks, trufflehog) via config.\n * Falls back to built-in scanner if external tool not available.\n */\nexport const scanForSecrets = async (filepaths: string[], tuckDir: string): Promise<ScanSummary> => {\n const config = await loadConfig(tuckDir);\n const security = config.security || {};\n\n // Check if an external scanner is configured\n const configuredScanner = (security.scanner || 'builtin') as ExternalScanner;\n\n // If external scanner configured, try to use it\n if (configuredScanner !== 'builtin') {\n // Check availability\n let useExternal = false;\n if (configuredScanner === 'gitleaks' && await isGitleaksInstalled()) {\n useExternal = true;\n } else if (configuredScanner === 'trufflehog' && await isTrufflehogInstalled()) {\n useExternal = true;\n }\n\n if (useExternal) {\n return scanWithScanner(filepaths, configuredScanner);\n }\n // Fall through to built-in if external not available\n }\n\n // Use built-in scanner with custom patterns\n const customPatterns: SecretPattern[] = (security.customPatterns || []).map((p: CustomPattern, i: number) =>\n createCustomPattern(`config-${i}`, p.name || `Custom Pattern ${i + 1}`, p.pattern, {\n severity: p.severity,\n description: p.description,\n placeholder: p.placeholder,\n flags: p.flags,\n })\n );\n\n return scanFiles(filepaths, {\n customPatterns: customPatterns.length > 0 ? customPatterns : undefined,\n excludePatternIds: security.excludePatterns,\n minSeverity: security.minSeverity,\n maxFileSize: security.maxFileSize,\n });\n};\n\n/**\n * Process scan results: store secrets and return placeholder mapping\n */\nexport const processSecretsForRedaction = async (\n results: FileScanResult[],\n tuckDir: string\n): Promise<Map<string, Map<string, string>>> => {\n await ensureSecretsGitignored(tuckDir);\n\n // Map of filepath -> (secret value -> placeholder name)\n const fileRedactionMaps = new Map<string, Map<string, string>>();\n\n // Track used placeholders to ensure uniqueness\n const usedPlaceholders = new Set<string>();\n\n for (const result of results) {\n const placeholderMap = new Map<string, string>();\n\n for (const match of result.matches) {\n // Check if we already have this value mapped\n let existingPlaceholder: string | undefined;\n \n // First check the current file's map to avoid duplicates within the same file\n if (placeholderMap.has(match.value)) {\n existingPlaceholder = placeholderMap.get(match.value);\n } else {\n // Then check previous files\n for (const map of fileRedactionMaps.values()) {\n if (map.has(match.value)) {\n existingPlaceholder = map.get(match.value);\n break;\n }\n }\n }\n\n let placeholder: string;\n if (existingPlaceholder) {\n // Reuse existing placeholder for same value\n placeholder = existingPlaceholder;\n } else {\n // Generate unique placeholder\n placeholder = match.placeholder;\n let counter = 1;\n while (usedPlaceholders.has(placeholder)) {\n placeholder = `${match.placeholder}_${counter}`;\n counter++;\n }\n usedPlaceholders.add(placeholder);\n\n // Store the secret\n await setSecret(tuckDir, placeholder, match.value, {\n description: match.patternName,\n source: result.collapsedPath,\n });\n }\n\n placeholderMap.set(match.value, placeholder);\n }\n\n fileRedactionMaps.set(result.path, placeholderMap);\n }\n\n return fileRedactionMaps;\n};\n\n/**\n * Check if secret scanning is enabled in config\n */\nexport const isSecretScanningEnabled = async (tuckDir: string): Promise<boolean> => {\n try {\n const config = await loadConfig(tuckDir);\n return config.security?.scanSecrets !== false;\n } catch (error) {\n // Log error for debugging instead of silent failure\n const errorMsg = error instanceof Error ? error.message : String(error);\n console.warn(`[tuck] Warning: Failed to load config for scanning check: ${errorMsg}`);\n // Default to enabled if config can't be loaded (safe default)\n return true;\n }\n};\n\n/**\n * Check if operations should be blocked when secrets are detected\n */\nexport const shouldBlockOnSecrets = async (tuckDir: string): Promise<boolean> => {\n try {\n const config = await loadConfig(tuckDir);\n return config.security?.blockOnSecrets !== false;\n } catch (error) {\n // Log error for debugging instead of silent failure\n const errorMsg = error instanceof Error ? error.message : String(error);\n console.warn(`[tuck] Warning: Failed to load config for blocking check: ${errorMsg}`);\n // Default to blocking if config can't be loaded (safe default)\n return true;\n }\n};\n","/**\n * tuck secrets - Manage local secrets for placeholder replacement\n *\n * Commands:\n * tuck secrets list - List all stored secrets (values hidden)\n * tuck secrets set <n> <v> - Set a secret value\n * tuck secrets unset <name> - Remove a secret\n * tuck secrets path - Show path to secrets file\n * tuck secrets scan-history - Scan git history for leaked secrets\n */\n\nimport { Command } from 'commander';\nimport { prompts, logger, colors as c } from '../ui/index.js';\nimport { getTuckDir, expandPath, pathExists } from '../lib/paths.js';\nimport { loadManifest } from '../lib/manifest.js';\nimport {\n listSecrets,\n setSecret,\n unsetSecret,\n getSecretsPath,\n isValidSecretName,\n normalizeSecretName,\n scanForSecrets,\n type ScanSummary,\n} from '../lib/secrets/index.js';\nimport { NotInitializedError } from '../errors.js';\nimport { getLog } from '../lib/git.js';\n\n// ============================================================================\n// List Command\n// ============================================================================\n\nconst runSecretsList = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n const secrets = await listSecrets(tuckDir);\n\n if (secrets.length === 0) {\n logger.info('No secrets stored');\n logger.dim(`Secrets file: ${getSecretsPath(tuckDir)}`);\n console.log();\n logger.dim('Secrets are stored when you choose to replace detected secrets with placeholders.');\n logger.dim('You can also manually add secrets with: tuck secrets set <NAME> <value>');\n return;\n }\n\n console.log();\n console.log(c.bold.cyan(`Stored Secrets (${secrets.length})`));\n console.log(c.dim('─'.repeat(50)));\n console.log();\n\n for (const secret of secrets) {\n console.log(` ${c.green(secret.name)}`);\n console.log(` ${c.dim('Placeholder:')} ${c.cyan(secret.placeholder)}`);\n if (secret.description) {\n console.log(` ${c.dim('Type:')} ${secret.description}`);\n }\n if (secret.source) {\n console.log(` ${c.dim('Source:')} ${secret.source}`);\n }\n console.log(` ${c.dim('Added:')} ${new Date(secret.addedAt).toLocaleDateString()}`);\n console.log();\n }\n\n logger.dim(`Secrets file: ${getSecretsPath(tuckDir)}`);\n};\n\n// ============================================================================\n// Set Command\n// ============================================================================\n\nconst runSecretsSet = async (name: string): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Validate or normalize name\n if (!isValidSecretName(name)) {\n const normalized = normalizeSecretName(name);\n logger.warning(`Secret name normalized to: ${normalized}`);\n logger.dim('Secret names must be uppercase alphanumeric with underscores (e.g., API_KEY)');\n name = normalized;\n }\n\n // Security: Always prompt for secret value interactively\n // Never accept via command-line to prevent exposure in shell history and process list\n // Note: Cancellation or empty input is handled below by validating the returned value.\n const secretValue = await prompts.password(`Enter value for ${name}:`);\n\n if (!secretValue || secretValue.trim().length === 0) {\n logger.error('Secret value cannot be empty');\n return;\n }\n\n await setSecret(tuckDir, name, secretValue);\n logger.success(`Secret '${name}' set`);\n console.log();\n logger.dim(`Use {{${name}}} as placeholder in your dotfiles`);\n};\n\n// ============================================================================\n// Unset Command\n// ============================================================================\n\nconst runSecretsUnset = async (name: string): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n const removed = await unsetSecret(tuckDir, name);\n\n if (removed) {\n logger.success(`Secret '${name}' removed`);\n } else {\n logger.warning(`Secret '${name}' not found`);\n logger.dim('Run `tuck secrets list` to see stored secrets');\n }\n};\n\n// ============================================================================\n// Path Command\n// ============================================================================\n\nconst runSecretsPath = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n console.log(getSecretsPath(tuckDir));\n};\n\n// ============================================================================\n// Scan History Command\n// ============================================================================\n\ninterface HistoryScanResult {\n commit: string;\n author: string;\n date: string;\n message: string;\n secrets: Array<{\n file: string;\n pattern: string;\n severity: string;\n redactedValue: string;\n }>;\n}\n\nconst runScanHistory = async (options: { since?: string; limit?: string }): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n const limit = options.limit ? parseInt(options.limit, 10) : 50;\n\n prompts.intro('tuck secrets scan-history');\n\n const spinner = prompts.spinner();\n spinner.start('Scanning git history for secrets...');\n\n try {\n // Get commit log using existing function\n const logEntries = await getLog(tuckDir, {\n maxCount: limit,\n since: options.since,\n });\n\n if (logEntries.length === 0) {\n spinner.stop('No commits found');\n return;\n }\n\n // Import simpleGit directly for diff operations\n let simpleGit;\n try {\n simpleGit = (await import('simple-git')).default;\n } catch (importError) {\n spinner.stop('Git integration is unavailable (simple-git module could not be loaded).');\n const errorMsg = importError instanceof Error ? importError.message : String(importError);\n logger.error(`Failed to load simple-git for scan-history: ${errorMsg}`);\n return;\n }\n const git = simpleGit(tuckDir);\n\n const results: HistoryScanResult[] = [];\n let scannedCommits = 0;\n\n for (const entry of logEntries) {\n scannedCommits++;\n spinner.message(`Scanning commit ${scannedCommits}/${logEntries.length}...`);\n\n // Get diff for this commit\n try {\n const diff = await git.diff([`${entry.hash}^`, entry.hash]);\n\n if (diff) {\n // Extract added lines (those starting with +)\n const addedLines = diff\n .split('\\n')\n .filter((line: string) => line.startsWith('+') && !line.startsWith('+++'))\n .map((line: string) => line.slice(1))\n .join('\\n');\n\n if (addedLines) {\n // Scan the added content\n const { scanContent } = await import('../lib/secrets/scanner.js');\n const matches = scanContent(addedLines);\n\n if (matches.length > 0) {\n results.push({\n commit: entry.hash.slice(0, 8),\n author: entry.author,\n date: entry.date,\n message: entry.message.slice(0, 50),\n secrets: matches.map((m) => ({\n file: 'diff',\n pattern: m.patternName,\n severity: m.severity,\n redactedValue: m.redactedValue,\n })),\n });\n }\n }\n }\n } catch (error) {\n // Skip commits that can't be diffed (e.g., initial commit), but log for visibility\n const errorMsg = error instanceof Error ? error.message : String(error);\n logger.warning(\n `Skipping commit ${entry.hash.slice(\n 0,\n 8\n )}: unable to diff against parent (possibly initial/root commit). ${errorMsg}`\n );\n continue;\n }\n }\n\n spinner.stop(`Scanned ${scannedCommits} commits`);\n\n if (results.length === 0) {\n console.log();\n logger.success('No secrets found in git history');\n prompts.outro('Clean history!');\n return;\n }\n\n // Display results\n console.log();\n console.log(c.bold.red(`Found potential secrets in ${results.length} commits`));\n console.log(c.dim('─'.repeat(60)));\n console.log();\n\n for (const result of results) {\n console.log(c.yellow(`Commit: ${result.commit}`));\n console.log(c.dim(` Author: ${result.author}`));\n console.log(c.dim(` Date: ${result.date}`));\n console.log(c.dim(` Message: ${result.message}`));\n console.log();\n\n for (const secret of result.secrets) {\n const severityColor =\n secret.severity === 'critical' ? c.red : secret.severity === 'high' ? c.yellow : c.dim;\n console.log(` ${severityColor(`[${secret.severity}]`)} ${secret.pattern}`);\n console.log(c.dim(` Value: ${secret.redactedValue}`));\n }\n console.log();\n }\n\n console.log(c.dim('─'.repeat(60)));\n console.log();\n logger.warning('If these secrets are still valid, rotate them immediately!');\n console.log();\n logger.dim('To remove secrets from git history, consider using:');\n logger.dim(' - git filter-branch');\n logger.dim(' - BFG Repo-Cleaner (https://rtyley.github.io/bfg-repo-cleaner/)');\n\n prompts.outro(c.red(`${results.length} commits with potential secrets`));\n } catch (error) {\n spinner.stop('Scan failed');\n throw error;\n }\n};\n\n// ============================================================================\n// Interactive Scan Command\n// ============================================================================\n\nconst runScanFiles = async (paths: string[]): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n if (paths.length === 0) {\n logger.error('No files specified');\n logger.dim('Usage: tuck secrets scan <file> [files...]');\n return;\n }\n\n // Expand paths\n const expandedPaths = paths.map((p) => expandPath(p));\n\n // Check files exist\n for (const path of expandedPaths) {\n if (!(await pathExists(path))) {\n logger.warning(`File not found: ${path}`);\n }\n }\n\n const existingPaths = [];\n for (const path of expandedPaths) {\n if (await pathExists(path)) {\n existingPaths.push(path);\n }\n }\n\n if (existingPaths.length === 0) {\n logger.error('No valid files to scan');\n return;\n }\n\n const spinner = prompts.spinner();\n spinner.start(`Scanning ${existingPaths.length} file(s)...`);\n\n const summary = await scanForSecrets(existingPaths, tuckDir);\n\n spinner.stop('Scan complete');\n\n if (summary.filesWithSecrets === 0) {\n console.log();\n logger.success('No secrets detected');\n return;\n }\n\n // Display results\n displayScanResults(summary);\n};\n\n/**\n * Display scan results in a formatted way\n */\nexport const displayScanResults = (summary: ScanSummary): void => {\n console.log();\n console.log(\n c.bold.red(\n `Found ${summary.totalSecrets} potential secret(s) in ${summary.filesWithSecrets} file(s)`\n )\n );\n console.log(c.dim('─'.repeat(60)));\n console.log();\n\n // Summary by severity\n if (summary.bySeverity.critical > 0) {\n console.log(c.red(` Critical: ${summary.bySeverity.critical}`));\n }\n if (summary.bySeverity.high > 0) {\n console.log(c.yellow(` High: ${summary.bySeverity.high}`));\n }\n if (summary.bySeverity.medium > 0) {\n console.log(c.blue(` Medium: ${summary.bySeverity.medium}`));\n }\n if (summary.bySeverity.low > 0) {\n console.log(c.dim(` Low: ${summary.bySeverity.low}`));\n }\n console.log();\n\n // Details by file\n for (const result of summary.results) {\n console.log(c.cyan(result.collapsedPath));\n\n for (const match of result.matches) {\n const severityColor =\n match.severity === 'critical'\n ? c.red\n : match.severity === 'high'\n ? c.yellow\n : match.severity === 'medium'\n ? c.blue\n : c.dim;\n\n console.log(\n ` ${c.dim(`Line ${match.line}:`)} ${severityColor(`[${match.severity}]`)} ${match.patternName}`\n );\n console.log(c.dim(` ${match.context}`));\n }\n console.log();\n }\n};\n\n// ============================================================================\n// Command Definition\n// ============================================================================\n\nexport const secretsCommand = new Command('secrets')\n .description('Manage local secrets for placeholder replacement')\n .action(async () => {\n // Default action: show list\n await runSecretsList();\n })\n .addCommand(\n new Command('list')\n .description('List all stored secrets (values hidden)')\n .action(runSecretsList)\n )\n .addCommand(\n new Command('set')\n .description('Set a secret value (prompts securely)')\n .argument('<name>', 'Secret name (e.g., GITHUB_TOKEN)')\n .action(runSecretsSet)\n )\n .addCommand(\n new Command('unset')\n .description('Remove a secret')\n .argument('<name>', 'Secret name to remove')\n .action(runSecretsUnset)\n )\n .addCommand(new Command('path').description('Show path to secrets file').action(runSecretsPath))\n .addCommand(\n new Command('scan')\n .description('Scan files for secrets')\n .argument('[paths...]', 'Files to scan')\n .action(runScanFiles)\n )\n .addCommand(\n new Command('scan-history')\n .description('Scan git history for leaked secrets')\n .option('--since <date>', 'Only scan commits after this date (e.g., 2024-01-01)')\n .option('--limit <n>', 'Maximum number of commits to scan', '50')\n .action(runScanHistory)\n );\n","import { Command } from 'commander';\nimport { join } from 'path';\nimport { prompts, logger, withSpinner, colors as c } from '../ui/index.js';\nimport { getTuckDir, expandPath, pathExists, collapsePath } from '../lib/paths.js';\nimport {\n loadManifest,\n getAllTrackedFiles,\n updateFileInManifest,\n removeFileFromManifest,\n getTrackedFileBySource,\n} from '../lib/manifest.js';\nimport { stageAll, commit, getStatus, push, hasRemote, fetch, pull } from '../lib/git.js';\nimport {\n copyFileOrDir,\n getFileChecksum,\n deleteFileOrDir,\n checkFileSizeThreshold,\n formatFileSize,\n SIZE_BLOCK_THRESHOLD,\n} from '../lib/files.js';\nimport { addToTuckignore, loadTuckignore, isIgnored } from '../lib/tuckignore.js';\nimport { runPreSyncHook, runPostSyncHook, type HookOptions } from '../lib/hooks.js';\nimport { NotInitializedError, SecretsDetectedError } from '../errors.js';\nimport type { SyncOptions, FileChange } from '../types.js';\nimport { detectDotfiles, DETECTION_CATEGORIES, type DetectedFile } from '../lib/detect.js';\nimport { trackFilesWithProgress, type FileToTrack } from '../lib/fileTracking.js';\nimport { scanForSecrets, isSecretScanningEnabled } from '../lib/secrets/index.js';\nimport { displayScanResults } from './secrets.js';\n\ninterface SyncResult {\n modified: string[];\n deleted: string[];\n commitHash?: string;\n // Note: There is no 'added' array because adding new files is done via 'tuck add', not 'tuck sync'.\n // The sync command only handles changes to already-tracked files.\n}\n\nconst detectChanges = async (tuckDir: string): Promise<FileChange[]> => {\n const files = await getAllTrackedFiles(tuckDir);\n const ignoredPaths = await loadTuckignore(tuckDir);\n const changes: FileChange[] = [];\n\n for (const [, file] of Object.entries(files)) {\n // Skip if in .tuckignore\n if (ignoredPaths.has(file.source)) {\n continue;\n }\n\n const sourcePath = expandPath(file.source);\n\n // Check if source still exists\n if (!(await pathExists(sourcePath))) {\n changes.push({\n path: file.source,\n status: 'deleted',\n source: file.source,\n destination: file.destination,\n });\n continue;\n }\n\n // Check if file has changed compared to stored checksum\n try {\n const sourceChecksum = await getFileChecksum(sourcePath);\n if (sourceChecksum !== file.checksum) {\n changes.push({\n path: file.source,\n status: 'modified',\n source: file.source,\n destination: file.destination,\n });\n }\n } catch {\n changes.push({\n path: file.source,\n status: 'modified',\n source: file.source,\n destination: file.destination,\n });\n }\n }\n\n return changes;\n};\n\n/**\n * Pull from remote if behind, returns info about what happened\n */\nconst pullIfBehind = async (\n tuckDir: string\n): Promise<{ pulled: boolean; behind: number; error?: string }> => {\n const hasRemoteRepo = await hasRemote(tuckDir);\n if (!hasRemoteRepo) {\n return { pulled: false, behind: 0 };\n }\n\n try {\n // Fetch to get latest remote status\n await fetch(tuckDir);\n\n const status = await getStatus(tuckDir);\n\n if (status.behind === 0) {\n return { pulled: false, behind: 0 };\n }\n\n // Pull with rebase to keep history clean\n await pull(tuckDir, { rebase: true });\n\n return { pulled: true, behind: status.behind };\n } catch (error) {\n return {\n pulled: false,\n behind: 0,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n};\n\n/**\n * Detect new dotfiles that are not already tracked\n */\nconst detectNewDotfiles = async (tuckDir: string): Promise<DetectedFile[]> => {\n // Get all detected dotfiles on the system\n const detected = await detectDotfiles();\n\n // Filter out already-tracked files, ignored files, and excluded patterns\n const newFiles: DetectedFile[] = [];\n\n for (const file of detected) {\n // Skip if already tracked\n const tracked = await getTrackedFileBySource(tuckDir, file.path);\n if (tracked) continue;\n\n // Skip if in .tuckignore\n if (await isIgnored(tuckDir, file.path)) continue;\n\n newFiles.push(file);\n }\n\n return newFiles;\n};\n\nconst generateCommitMessage = (result: SyncResult): string => {\n const totalCount = result.modified.length + result.deleted.length;\n const date = new Date().toISOString().split('T')[0];\n\n // Header with emoji and count\n let message = `✨ Update dotfiles\\n\\n`;\n\n // List changes\n const changes: string[] = [];\n\n if (result.modified.length > 0) {\n if (result.modified.length <= 5) {\n // List individual files if 5 or fewer\n changes.push('Modified:');\n result.modified.forEach((file) => {\n changes.push(`• ${file}`);\n });\n } else {\n changes.push(`Modified: ${result.modified.length} files`);\n }\n }\n\n if (result.deleted.length > 0) {\n if (result.deleted.length <= 5) {\n changes.push(result.modified.length > 0 ? '\\nDeleted:' : 'Deleted:');\n result.deleted.forEach((file) => {\n changes.push(`• ${file}`);\n });\n } else {\n changes.push(\n `${result.modified.length > 0 ? '\\n' : ''}Deleted: ${result.deleted.length} files`\n );\n }\n }\n\n if (changes.length > 0) {\n message += changes.join('\\n') + '\\n';\n }\n\n // Footer with branding and metadata\n message += `\\n---\\n`;\n message += `📦 Managed by tuck (tuck.sh) • ${date}`;\n\n if (totalCount > 0) {\n message += ` • ${totalCount} file${totalCount > 1 ? 's' : ''} changed`;\n }\n\n return message;\n};\n\nconst syncFiles = async (\n tuckDir: string,\n changes: FileChange[],\n options: SyncOptions\n): Promise<SyncResult> => {\n const result: SyncResult = {\n modified: [],\n deleted: [],\n };\n\n // Prepare hook options\n const hookOptions: HookOptions = {\n skipHooks: options.noHooks,\n trustHooks: options.trustHooks,\n };\n\n // Run pre-sync hook\n await runPreSyncHook(tuckDir, hookOptions);\n\n // Process each change\n for (const change of changes) {\n const sourcePath = expandPath(change.source);\n const destPath = join(tuckDir, change.destination!);\n\n if (change.status === 'modified') {\n await withSpinner(`Syncing ${change.path}...`, async () => {\n await copyFileOrDir(sourcePath, destPath, { overwrite: true });\n\n // Update checksum in manifest\n const newChecksum = await getFileChecksum(destPath);\n const files = await getAllTrackedFiles(tuckDir);\n const fileId = Object.entries(files).find(([, f]) => f.source === change.source)?.[0];\n\n if (fileId) {\n await updateFileInManifest(tuckDir, fileId, {\n checksum: newChecksum,\n modified: new Date().toISOString(),\n });\n }\n });\n result.modified.push(change.path.split('/').pop() || change.path);\n } else if (change.status === 'deleted') {\n await withSpinner(`Removing ${change.path}...`, async () => {\n // Delete the file from the tuck repository\n await deleteFileOrDir(destPath);\n\n // Remove from manifest\n const files = await getAllTrackedFiles(tuckDir);\n const fileId = Object.entries(files).find(([, f]) => f.source === change.source)?.[0];\n\n if (fileId) {\n await removeFileFromManifest(tuckDir, fileId);\n }\n });\n result.deleted.push(change.path.split('/').pop() || change.path);\n }\n }\n\n // Stage and commit if not --no-commit\n if (!options.noCommit && (result.modified.length > 0 || result.deleted.length > 0)) {\n await withSpinner('Staging changes...', async () => {\n await stageAll(tuckDir);\n });\n\n const message = options.message || generateCommitMessage(result);\n\n await withSpinner('Committing...', async () => {\n result.commitHash = await commit(tuckDir, message);\n });\n }\n\n // Run post-sync hook\n await runPostSyncHook(tuckDir, hookOptions);\n\n return result;\n};\n\n/**\n * Scan modified files for secrets and handle user interaction\n * Returns true if sync should continue, false if aborted\n */\nconst scanAndHandleSecrets = async (\n tuckDir: string,\n changes: FileChange[],\n options: SyncOptions\n): Promise<boolean> => {\n // Skip if force flag is set or scanning is disabled\n if (options.force) {\n return true;\n }\n\n // Check if scanning is enabled in config\n const scanningEnabled = await isSecretScanningEnabled(tuckDir);\n if (!scanningEnabled) {\n return true;\n }\n\n // Get paths of modified files (not deleted)\n const modifiedPaths = changes\n .filter((c) => c.status === 'modified')\n .map((c) => expandPath(c.source));\n\n if (modifiedPaths.length === 0) {\n return true;\n }\n\n // Scan files\n const spinner = prompts.spinner();\n spinner.start('Scanning for secrets...');\n const summary = await scanForSecrets(modifiedPaths, tuckDir);\n spinner.stop('Scan complete');\n\n if (summary.totalSecrets === 0) {\n return true;\n }\n\n // Display results\n displayScanResults(summary);\n\n // Prompt user for action\n const action = await prompts.select('What would you like to do?', [\n { value: 'abort', label: 'Abort sync' },\n { value: 'ignore', label: 'Add files to .tuckignore and skip them' },\n { value: 'proceed', label: 'Proceed anyway (secrets will be committed)' },\n ]);\n\n if (action === 'abort') {\n prompts.cancel('Sync aborted - secrets detected');\n return false;\n }\n\n if (action === 'ignore') {\n // Add files with secrets to .tuckignore\n for (const result of summary.results) {\n const sourcePath = changes.find((c) => expandPath(c.source) === result.path)?.source;\n if (sourcePath) {\n await addToTuckignore(tuckDir, sourcePath);\n logger.dim(`Added ${collapsePath(result.path)} to .tuckignore`);\n }\n }\n // Filter out ignored files from changes list\n // Note: This intentionally mutates the 'changes' array in place so callers see the filtered list\n const filesToRemove = new Set(summary.results.map((r) => r.path));\n changes.splice(\n 0,\n changes.length,\n ...changes.filter((c) => !filesToRemove.has(expandPath(c.source)))\n );\n\n if (changes.length === 0) {\n prompts.log.info('No remaining changes to sync');\n return false;\n }\n return true;\n }\n\n // proceed - continue with warning\n prompts.log.warning('Proceeding with secrets - make sure your repo is private!');\n return true;\n};\n\nconst runInteractiveSync = async (tuckDir: string, options: SyncOptions = {}): Promise<void> => {\n prompts.intro('tuck sync');\n\n // ========== STEP 1: Pull from remote if behind ==========\n if (options.pull !== false && (await hasRemote(tuckDir))) {\n const pullSpinner = prompts.spinner();\n pullSpinner.start('Checking remote for updates...');\n\n const pullResult = await pullIfBehind(tuckDir);\n if (pullResult.error) {\n pullSpinner.stop(`Could not pull: ${pullResult.error}`);\n prompts.log.warning('Continuing with local changes...');\n } else if (pullResult.pulled) {\n pullSpinner.stop(\n `Pulled ${pullResult.behind} commit${pullResult.behind > 1 ? 's' : ''} from remote`\n );\n } else {\n pullSpinner.stop('Up to date with remote');\n }\n }\n\n // ========== STEP 2: Detect changes to tracked files ==========\n const changeSpinner = prompts.spinner();\n changeSpinner.start('Detecting changes to tracked files...');\n const changes = await detectChanges(tuckDir);\n changeSpinner.stop(`Found ${changes.length} changed file${changes.length !== 1 ? 's' : ''}`);\n\n // ========== STEP 2.5: Scan modified files for secrets ==========\n if (changes.length > 0) {\n const shouldContinue = await scanAndHandleSecrets(tuckDir, changes, options);\n if (!shouldContinue) {\n return;\n }\n }\n\n // ========== STEP 3: Scan for new dotfiles (if enabled) ==========\n let newFiles: DetectedFile[] = [];\n if (options.scan !== false) {\n const scanSpinner = prompts.spinner();\n scanSpinner.start('Scanning for new dotfiles...');\n newFiles = await detectNewDotfiles(tuckDir);\n scanSpinner.stop(`Found ${newFiles.length} new dotfile${newFiles.length !== 1 ? 's' : ''}`);\n }\n\n // ========== STEP 4: Handle case where nothing to do ==========\n if (changes.length === 0 && newFiles.length === 0) {\n const gitStatus = await getStatus(tuckDir);\n if (gitStatus.hasChanges) {\n prompts.log.info('No dotfile changes, but repository has uncommitted changes');\n\n const commitAnyway = await prompts.confirm('Commit repository changes?');\n if (commitAnyway) {\n const message = await prompts.text('Commit message:', {\n defaultValue: 'Update dotfiles',\n });\n\n await stageAll(tuckDir);\n const hash = await commit(tuckDir, message);\n prompts.log.success(`Committed: ${hash.slice(0, 7)}`);\n\n // Push if remote exists\n if (options.push !== false && (await hasRemote(tuckDir))) {\n await pushWithSpinner(tuckDir, options);\n }\n }\n } else {\n prompts.log.success('Everything is up to date');\n }\n return;\n }\n\n // ========== STEP 5: Show changes to tracked files ==========\n if (changes.length > 0) {\n console.log();\n console.log(c.bold('Changes to tracked files:'));\n for (const change of changes) {\n if (change.status === 'modified') {\n console.log(c.yellow(` ~ ${change.path}`));\n } else if (change.status === 'deleted') {\n console.log(c.red(` - ${change.path}`));\n }\n }\n }\n\n // ========== STEP 6: Interactive selection for new files ==========\n let filesToTrack: FileToTrack[] = [];\n\n if (newFiles.length > 0) {\n console.log();\n console.log(c.bold(`New dotfiles found (${newFiles.length}):`));\n\n // Group by category for display\n const grouped: Record<string, DetectedFile[]> = {};\n for (const file of newFiles) {\n if (!grouped[file.category]) grouped[file.category] = [];\n grouped[file.category].push(file);\n }\n\n for (const [category, files] of Object.entries(grouped)) {\n const categoryInfo = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n console.log(\n c.cyan(\n ` ${categoryInfo.icon} ${categoryInfo.name}: ${files.length} file${files.length > 1 ? 's' : ''}`\n )\n );\n }\n\n console.log();\n const trackNewFiles = await prompts.confirm(\n 'Would you like to track some of these new files?',\n true\n );\n\n if (trackNewFiles) {\n // Create multiselect options (pre-select non-sensitive files)\n const selectOptions = newFiles.map((f) => ({\n value: f.path,\n label: `${collapsePath(expandPath(f.path))}${f.sensitive ? c.yellow(' [sensitive]') : ''}`,\n hint: f.category,\n }));\n\n const nonSensitiveFiles = newFiles.filter((f) => !f.sensitive);\n const initialValues = nonSensitiveFiles.map((f) => f.path);\n\n const selected = await prompts.multiselect('Select files to track:', selectOptions, {\n initialValues,\n });\n\n filesToTrack = selected.map((path) => ({ path: path as string }));\n }\n }\n\n // ========== STEP 7: Handle large files in tracked changes ==========\n const largeFiles: Array<{ path: string; size: string; sizeBytes: number }> = [];\n\n for (const change of changes) {\n if (change.status !== 'deleted') {\n const expandedPath = expandPath(change.source);\n const sizeCheck = await checkFileSizeThreshold(expandedPath);\n\n if (sizeCheck.warn || sizeCheck.block) {\n largeFiles.push({\n path: change.path,\n size: formatFileSize(sizeCheck.size),\n sizeBytes: sizeCheck.size,\n });\n }\n }\n }\n\n if (largeFiles.length > 0) {\n console.log();\n console.log(c.yellow('Large files detected:'));\n for (const file of largeFiles) {\n console.log(c.yellow(` ${file.path} (${file.size})`));\n }\n console.log();\n console.log(c.dim('GitHub has a 50MB warning and 100MB hard limit.'));\n console.log();\n\n const hasBlockers = largeFiles.some((f) => f.sizeBytes >= SIZE_BLOCK_THRESHOLD);\n\n if (hasBlockers) {\n const action = await prompts.select('Some files exceed 100MB. What would you like to do?', [\n { value: 'ignore', label: 'Add large files to .tuckignore' },\n { value: 'continue', label: 'Try to commit anyway (may fail)' },\n { value: 'cancel', label: 'Cancel sync' },\n ]);\n\n if (action === 'ignore') {\n for (const file of largeFiles) {\n const fullPath = changes.find((c) => c.path === file.path)?.source;\n if (fullPath) {\n await addToTuckignore(tuckDir, fullPath);\n const index = changes.findIndex((c) => c.path === file.path);\n if (index > -1) changes.splice(index, 1);\n }\n }\n prompts.log.success('Added large files to .tuckignore');\n\n if (changes.length === 0 && filesToTrack.length === 0) {\n prompts.log.info('No changes remaining to sync');\n return;\n }\n } else if (action === 'cancel') {\n prompts.cancel('Operation cancelled');\n return;\n }\n } else {\n const action = await prompts.select('Large files detected. What would you like to do?', [\n { value: 'continue', label: 'Continue with sync' },\n { value: 'ignore', label: 'Add to .tuckignore and skip' },\n { value: 'cancel', label: 'Cancel sync' },\n ]);\n\n if (action === 'ignore') {\n for (const file of largeFiles) {\n const fullPath = changes.find((c) => c.path === file.path)?.source;\n if (fullPath) {\n await addToTuckignore(tuckDir, fullPath);\n const index = changes.findIndex((c) => c.path === file.path);\n if (index > -1) changes.splice(index, 1);\n }\n }\n prompts.log.success('Added large files to .tuckignore');\n\n if (changes.length === 0 && filesToTrack.length === 0) {\n prompts.log.info('No changes remaining to sync');\n return;\n }\n } else if (action === 'cancel') {\n prompts.cancel('Operation cancelled');\n return;\n }\n }\n }\n\n // ========== STEP 8: Track new files ==========\n if (filesToTrack.length > 0) {\n console.log();\n await trackFilesWithProgress(filesToTrack, tuckDir, {\n showCategory: true,\n actionVerb: 'Tracking',\n });\n }\n\n // ========== STEP 9: Sync changes to tracked files ==========\n let result: SyncResult = { modified: [], deleted: [] };\n\n if (changes.length > 0) {\n // Generate commit message\n const message =\n options.message ||\n generateCommitMessage({\n modified: changes.filter((c) => c.status === 'modified').map((c) => c.path),\n deleted: changes.filter((c) => c.status === 'deleted').map((c) => c.path),\n });\n\n console.log();\n console.log(c.dim('Commit message:'));\n console.log(\n c.cyan(\n message\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n')\n )\n );\n console.log();\n\n result = await syncFiles(tuckDir, changes, { ...options, message });\n } else if (filesToTrack.length > 0) {\n // Only new files were added, commit them\n if (!options.noCommit) {\n const message =\n options.message ||\n `Add ${filesToTrack.length} new dotfile${filesToTrack.length > 1 ? 's' : ''}`;\n await stageAll(tuckDir);\n result.commitHash = await commit(tuckDir, message);\n }\n }\n\n // ========== STEP 10: Push to remote ==========\n console.log();\n let pushFailed = false;\n\n if (result.commitHash) {\n prompts.log.success(`Committed: ${result.commitHash.slice(0, 7)}`);\n\n if (options.push !== false && (await hasRemote(tuckDir))) {\n pushFailed = !(await pushWithSpinner(tuckDir, options));\n } else if (options.push === false) {\n prompts.log.info(\"Run 'tuck push' when ready to upload\");\n }\n }\n\n // Only show success if no push failure occurred\n if (!pushFailed) {\n prompts.outro('Synced successfully!');\n }\n};\n\n/**\n * Helper to push with spinner and error handling\n */\nconst pushWithSpinner = async (tuckDir: string, _options: SyncOptions): Promise<boolean> => {\n const spinner = prompts.spinner();\n try {\n const status = await getStatus(tuckDir);\n const needsUpstream = !status.tracking;\n const branch = status.branch;\n\n spinner.start('Pushing to remote...');\n await push(tuckDir, {\n setUpstream: needsUpstream,\n branch: needsUpstream ? branch : undefined,\n });\n spinner.stop('Pushed to remote');\n return true;\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n spinner.stop(`Push failed: ${errorMsg}`);\n prompts.log.warning(\"Run 'tuck push' to try again\");\n return false;\n }\n};\n\n/**\n * Run sync programmatically (exported for use by other commands)\n */\nexport const runSync = async (options: SyncOptions = {}): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Always run interactive sync when called programmatically\n await runInteractiveSync(tuckDir, options);\n};\n\nconst runSyncCommand = async (\n messageArg: string | undefined,\n options: SyncOptions\n): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // If no options (except --no-push), run interactive\n if (!messageArg && !options.message && !options.noCommit) {\n await runInteractiveSync(tuckDir, options);\n return;\n }\n\n // Detect changes\n const changes = await detectChanges(tuckDir);\n\n if (changes.length === 0) {\n logger.info('No changes detected');\n return;\n }\n\n // Scan for secrets (non-interactive mode - throw error if found)\n if (!options.force) {\n const scanningEnabled = await isSecretScanningEnabled(tuckDir);\n if (scanningEnabled) {\n const modifiedPaths = changes\n .filter((c) => c.status === 'modified')\n .map((c) => expandPath(c.source));\n\n if (modifiedPaths.length > 0) {\n const summary = await scanForSecrets(modifiedPaths, tuckDir);\n if (summary.totalSecrets > 0) {\n displayScanResults(summary);\n throw new SecretsDetectedError(\n summary.totalSecrets,\n summary.results.map((r) => collapsePath(r.path))\n );\n }\n }\n }\n }\n\n // Show changes\n logger.heading('Changes detected:');\n for (const change of changes) {\n logger.file(change.status === 'modified' ? 'modify' : 'delete', change.path);\n }\n logger.blank();\n\n // Sync\n const message = messageArg || options.message;\n const result = await syncFiles(tuckDir, changes, { ...options, message });\n\n logger.blank();\n logger.success(`Synced ${changes.length} file${changes.length > 1 ? 's' : ''}`);\n\n if (result.commitHash) {\n logger.info(`Commit: ${result.commitHash.slice(0, 7)}`);\n\n // Push by default unless --no-push\n // Commander converts --no-push to push: false, default is push: true\n if (options.push !== false && (await hasRemote(tuckDir))) {\n await withSpinner('Pushing to remote...', async () => {\n await push(tuckDir);\n });\n logger.success('Pushed to remote');\n } else if (options.push === false) {\n logger.info(\"Run 'tuck push' when ready to upload\");\n }\n }\n};\n\nexport const syncCommand = new Command('sync')\n .description(\n 'Sync all dotfile changes (pull, detect changes, scan for new files, track, commit, push)'\n )\n .argument('[message]', 'Commit message')\n .option('-m, --message <msg>', 'Commit message')\n // TODO: --all and --amend are planned for a future version\n // .option('-a, --all', 'Sync all tracked files, not just changed')\n // .option('--amend', 'Amend previous commit')\n .option('--no-commit', \"Stage changes but don't commit\")\n .option('--no-push', \"Commit but don't push to remote\")\n .option('--no-pull', \"Don't pull from remote first\")\n .option('--no-scan', \"Don't scan for new dotfiles\")\n .option('--no-hooks', 'Skip execution of pre/post sync hooks')\n .option('--trust-hooks', 'Trust and run hooks without confirmation (use with caution)')\n .option('-f, --force', 'Skip secret scanning (not recommended)')\n .action(async (messageArg: string | undefined, options: SyncOptions) => {\n await runSyncCommand(messageArg, options);\n });\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport {\n initCommand,\n addCommand,\n removeCommand,\n syncCommand,\n pushCommand,\n pullCommand,\n restoreCommand,\n statusCommand,\n listCommand,\n diffCommand,\n configCommand,\n applyCommand,\n undoCommand,\n scanCommand,\n secretsCommand,\n} from './commands/index.js';\nimport { handleError } from './errors.js';\nimport { VERSION, DESCRIPTION } from './constants.js';\nimport { customHelp, miniBanner } from './ui/banner.js';\nimport { getTuckDir, pathExists } from './lib/paths.js';\nimport { loadManifest } from './lib/manifest.js';\nimport { getStatus } from './lib/git.js';\n\nconst program = new Command();\n\nprogram\n .name('tuck')\n .description(DESCRIPTION)\n .version(VERSION, '-v, --version', 'Display version number')\n .configureOutput({\n outputError: (str, write) => write(chalk.red(str)),\n })\n .addHelpText('before', customHelp(VERSION))\n .helpOption('-h, --help', 'Display this help message')\n .showHelpAfterError(false);\n\n// Register commands\nprogram.addCommand(initCommand);\nprogram.addCommand(addCommand);\nprogram.addCommand(removeCommand);\nprogram.addCommand(syncCommand);\nprogram.addCommand(pushCommand);\nprogram.addCommand(pullCommand);\nprogram.addCommand(restoreCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(listCommand);\nprogram.addCommand(diffCommand);\nprogram.addCommand(configCommand);\nprogram.addCommand(applyCommand);\nprogram.addCommand(undoCommand);\nprogram.addCommand(scanCommand);\nprogram.addCommand(secretsCommand);\n\n// Default action when no command is provided\nconst runDefaultAction = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Check if tuck is initialized\n if (!(await pathExists(tuckDir))) {\n miniBanner();\n console.log(chalk.bold('Get started with tuck:\\n'));\n console.log(chalk.cyan(' tuck init') + chalk.dim(' - Set up tuck and create a GitHub repo'));\n console.log(chalk.cyan(' tuck scan') + chalk.dim(' - Find dotfiles to track'));\n console.log();\n console.log(chalk.dim('On a new machine:'));\n console.log(chalk.cyan(' tuck apply <username>') + chalk.dim(' - Apply your dotfiles'));\n console.log();\n return;\n }\n\n // Load manifest to check status\n try {\n const manifest = await loadManifest(tuckDir);\n const trackedCount = Object.keys(manifest.files).length;\n const gitStatus = await getStatus(tuckDir);\n\n miniBanner();\n console.log(chalk.bold('Status:\\n'));\n\n // Show tracked files count\n console.log(` Tracked files: ${chalk.cyan(trackedCount.toString())}`);\n\n // Show git status\n const pendingChanges = gitStatus.modified.length + gitStatus.staged.length;\n if (pendingChanges > 0) {\n console.log(` Pending changes: ${chalk.yellow(pendingChanges.toString())}`);\n } else {\n console.log(` Pending changes: ${chalk.dim('none')}`);\n }\n\n // Show remote status\n if (gitStatus.ahead > 0) {\n console.log(` Commits to push: ${chalk.yellow(gitStatus.ahead.toString())}`);\n }\n\n console.log();\n\n // Show what to do next\n console.log(chalk.bold('Next steps:\\n'));\n\n if (trackedCount === 0) {\n console.log(chalk.cyan(' tuck scan') + chalk.dim(' - Find dotfiles to track'));\n console.log(chalk.cyan(' tuck add <file>') + chalk.dim(' - Track a specific file'));\n } else if (pendingChanges > 0) {\n console.log(chalk.cyan(' tuck sync') + chalk.dim(' - Commit and push your changes'));\n console.log(chalk.cyan(' tuck diff') + chalk.dim(' - Preview what changed'));\n } else if (gitStatus.ahead > 0) {\n console.log(chalk.cyan(' tuck push') + chalk.dim(' - Push commits to GitHub'));\n } else {\n console.log(chalk.dim(' All synced! Your dotfiles are up to date.'));\n console.log();\n console.log(chalk.cyan(' tuck scan') + chalk.dim(' - Find more dotfiles to track'));\n console.log(chalk.cyan(' tuck list') + chalk.dim(' - See tracked files'));\n }\n\n console.log();\n } catch {\n // Manifest load failed, treat as not initialized\n miniBanner();\n console.log(chalk.yellow('Tuck directory exists but may be corrupted.'));\n console.log(chalk.dim('Run `tuck init` to reinitialize.'));\n console.log();\n }\n};\n\n// Check if no command provided\nconst hasCommand = process.argv\n .slice(2)\n .some((arg) => !arg.startsWith('-') && arg !== '--help' && arg !== '-h');\n\n// Global error handling\nprocess.on('uncaughtException', handleError);\nprocess.on('unhandledRejection', (reason) => {\n handleError(reason instanceof Error ? reason : new Error(String(reason)));\n});\n\n// Parse and execute\nif (\n !hasCommand &&\n !process.argv.includes('--help') &&\n !process.argv.includes('-h') &&\n !process.argv.includes('--version') &&\n !process.argv.includes('-v')\n) {\n runDefaultAction().catch(handleError);\n} else {\n program.parseAsync(process.argv).catch(handleError);\n}\n","import { Command } from 'commander';\nimport { join } from 'path';\nimport { writeFile } from 'fs/promises';\nimport { ensureDir } from 'fs-extra';\nimport { banner, nextSteps, prompts, withSpinner, logger, colors as c } from '../ui/index.js';\nimport {\n getTuckDir,\n getManifestPath,\n getConfigPath,\n getFilesDir,\n getCategoryDir,\n pathExists,\n collapsePath,\n} from '../lib/paths.js';\nimport { saveConfig } from '../lib/config.js';\nimport { createManifest } from '../lib/manifest.js';\nimport type { TuckManifest } from '../types.js';\nimport {\n initRepo,\n addRemote,\n cloneRepo,\n setDefaultBranch,\n stageAll,\n commit,\n push,\n} from '../lib/git.js';\nimport {\n isGhInstalled,\n isGhAuthenticated,\n getAuthenticatedUser,\n createRepo,\n getPreferredRepoUrl,\n getPreferredRemoteProtocol,\n findDotfilesRepo,\n ghCloneRepo,\n checkSSHKeys,\n testSSHConnection,\n getSSHKeyInstructions,\n getFineGrainedTokenInstructions,\n getClassicTokenInstructions,\n getGitHubCLIInstallInstructions,\n storeGitHubCredentials,\n detectTokenType,\n configureGitCredentialHelper,\n testStoredCredentials,\n diagnoseAuthIssue,\n MIN_GITHUB_TOKEN_LENGTH,\n GITHUB_TOKEN_PREFIXES,\n} from '../lib/github.js';\nimport { detectDotfiles, DetectedFile, DETECTION_CATEGORIES } from '../lib/detect.js';\nimport { copy } from 'fs-extra';\nimport { tmpdir } from 'os';\nimport { readFile, rm } from 'fs/promises';\nimport { AlreadyInitializedError } from '../errors.js';\nimport { CATEGORIES } from '../constants.js';\nimport { defaultConfig } from '../schemas/config.schema.js';\nimport type { InitOptions } from '../types.js';\nimport { trackFilesWithProgress, type FileToTrack } from '../lib/fileTracking.js';\n\nconst GITIGNORE_TEMPLATE = `# OS generated files\n.DS_Store\n.DS_Store?\n._*\n.Spotlight-V100\n.Trashes\nehthumbs.db\nThumbs.db\n\n# Backup files\n*.bak\n*.backup\n*~\n\n# Secret files (add patterns for files you want to exclude)\n# *.secret\n# .env.local\n`;\n\n/**\n * Track selected files with beautiful progress display\n */\nconst trackFilesWithProgressInit = async (\n selectedPaths: string[],\n tuckDir: string\n): Promise<number> => {\n // Convert paths to FileToTrack\n const filesToTrack: FileToTrack[] = selectedPaths.map((path) => ({\n path,\n }));\n\n // Use the shared tracking utility\n const result = await trackFilesWithProgress(filesToTrack, tuckDir, {\n showCategory: true,\n actionVerb: 'Tracking',\n });\n\n return result.succeeded;\n};\n\nconst README_TEMPLATE = (machine?: string) => `# Dotfiles\n\nManaged with [tuck](https://github.com/Pranav-Karra-3301/tuck) - Modern Dotfiles Manager\n\n${machine ? `## Machine: ${machine}\\n` : ''}\n\n## Quick Start\n\n\\`\\`\\`bash\n# Restore dotfiles to a new machine\ntuck init --from <this-repo-url>\n\n# Or clone and restore manually\ngit clone <this-repo-url> ~/.tuck\ntuck restore --all\n\\`\\`\\`\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| \\`tuck add <paths>\\` | Track new dotfiles |\n| \\`tuck sync\\` | Sync changes to repository |\n| \\`tuck push\\` | Push to remote |\n| \\`tuck pull\\` | Pull from remote |\n| \\`tuck restore\\` | Restore dotfiles to system |\n| \\`tuck status\\` | Show tracking status |\n| \\`tuck list\\` | List tracked files |\n\n## Structure\n\n\\`\\`\\`\n.tuck/\n├── files/ # Tracked dotfiles organized by category\n│ ├── shell/ # Shell configs (.zshrc, .bashrc, etc.)\n│ ├── git/ # Git configs (.gitconfig, etc.)\n│ ├── editors/ # Editor configs (nvim, vim, etc.)\n│ ├── terminal/ # Terminal configs (tmux, alacritty, etc.)\n│ └── misc/ # Other dotfiles\n├── .tuckmanifest.json # Tracks all managed files\n└── .tuckrc.json # Tuck configuration\n\\`\\`\\`\n`;\n\n/**\n * Validates a GitHub repository URL (HTTPS or SSH format) and checks for owner/repo pattern\n * @param value The URL to validate\n * @returns undefined if valid, or an error message string if invalid\n */\nconst validateGitHubUrl = (value: string): string | undefined => {\n if (!value) return 'Repository URL is required';\n\n const isGitHubHttps = value.startsWith('https://github.com/');\n const isGitHubSsh = value.startsWith('git@github.com:');\n\n if (!isGitHubHttps && !isGitHubSsh) {\n return 'Please enter a valid GitHub URL';\n }\n\n // Validate URL contains owner/repo pattern\n if (isGitHubHttps) {\n // HTTPS format: https://github.com/owner/repo[.git]\n const pathPart = value.substring('https://github.com/'.length);\n if (!pathPart.includes('/') || pathPart === '/') {\n return 'GitHub URL must include owner and repository name (e.g., https://github.com/owner/repo)';\n }\n } else if (isGitHubSsh) {\n // SSH format: git@github.com:owner/repo[.git]\n const pathPart = value.substring('git@github.com:'.length);\n if (!pathPart.includes('/') || pathPart === '/') {\n return 'GitHub URL must include owner and repository name (e.g., git@github.com:owner/repo.git)';\n }\n }\n\n return undefined;\n};\n\n/**\n * Validate any Git repository URL (not just GitHub)\n * Used when cloning existing repositories that may be hosted anywhere\n */\nconst validateGitUrl = (value: string): string | undefined => {\n if (!value) return 'Repository URL is required';\n\n const trimmed = value.trim();\n\n // Check for common Git URL patterns\n const isHttps = /^https?:\\/\\/.+\\/.+/.test(trimmed); // Must have at least host/path\n const isSshScp = /^[^@]+@[^@:]+:[^:]+\\/.+/.test(trimmed); // e.g. git@host:user/repo.git\n const isSshUrl = /^ssh:\\/\\/.+\\/.+/.test(trimmed); // e.g. ssh://git@host/user/repo.git\n\n if (!isHttps && !isSshScp && !isSshUrl) {\n return 'Please enter a valid Git repository URL (HTTPS or SSH format)';\n }\n\n return undefined;\n};\n\nconst createDirectoryStructure = async (tuckDir: string): Promise<void> => {\n // Create main directories\n await ensureDir(tuckDir);\n await ensureDir(getFilesDir(tuckDir));\n\n // Create category directories\n for (const category of Object.keys(CATEGORIES)) {\n await ensureDir(getCategoryDir(tuckDir, category));\n }\n};\n\nconst createDefaultFiles = async (tuckDir: string, machine?: string): Promise<void> => {\n // Create .gitignore only if it doesn't exist\n const gitignorePath = join(tuckDir, '.gitignore');\n if (!(await pathExists(gitignorePath))) {\n await writeFile(gitignorePath, GITIGNORE_TEMPLATE, 'utf-8');\n }\n\n // Create README.md only if it doesn't exist\n const readmePath = join(tuckDir, 'README.md');\n if (!(await pathExists(readmePath))) {\n await writeFile(readmePath, README_TEMPLATE(machine), 'utf-8');\n }\n};\n\nconst initFromScratch = async (\n tuckDir: string,\n options: { remote?: string; bare?: boolean }\n): Promise<void> => {\n // Check if already initialized\n if (await pathExists(getManifestPath(tuckDir))) {\n throw new AlreadyInitializedError(tuckDir);\n }\n\n // Create directory structure\n await withSpinner('Creating directory structure...', async () => {\n await createDirectoryStructure(tuckDir);\n });\n\n // Initialize git repository\n await withSpinner('Initializing git repository...', async () => {\n await initRepo(tuckDir);\n await setDefaultBranch(tuckDir, 'main');\n });\n\n // Create manifest\n await withSpinner('Creating manifest...', async () => {\n const hostname = (await import('os')).hostname();\n await createManifest(tuckDir, hostname);\n });\n\n // Create config\n await withSpinner('Creating configuration...', async () => {\n await saveConfig(\n {\n ...defaultConfig,\n repository: { ...defaultConfig.repository, path: tuckDir },\n },\n tuckDir\n );\n });\n\n // Create default files unless --bare\n if (!options.bare) {\n await withSpinner('Creating default files...', async () => {\n const hostname = (await import('os')).hostname();\n await createDefaultFiles(tuckDir, hostname);\n });\n }\n\n // Add remote if provided\n if (options.remote) {\n await withSpinner('Adding remote...', async () => {\n await addRemote(tuckDir, 'origin', options.remote!);\n });\n }\n};\n\ninterface GitHubSetupResult {\n remoteUrl: string | null;\n pushed: boolean;\n}\n\n/**\n * Set up alternative authentication (SSH or tokens)\n */\nconst setupAlternativeAuth = async (tuckDir: string): Promise<GitHubSetupResult> => {\n console.log();\n prompts.log.info(\"GitHub CLI not available. Let's set up authentication another way.\");\n console.log();\n\n // Check for existing credentials and test them\n const credTest = await testStoredCredentials();\n if (credTest.valid && credTest.username) {\n prompts.log.success(`Found existing valid credentials for ${credTest.username}`);\n const useExisting = await prompts.confirm('Use these credentials?', true);\n if (useExisting) {\n // Credentials work - ask for repo URL\n return await promptForManualRepoUrl(tuckDir, credTest.username);\n }\n } else if (credTest.username && credTest.reason) {\n // Had credentials but they failed\n const diagnosis = await diagnoseAuthIssue();\n prompts.log.warning(diagnosis.issue);\n for (const suggestion of diagnosis.suggestions) {\n console.log(c.muted(` ${suggestion}`));\n }\n console.log();\n }\n\n // Check for existing SSH keys\n const sshInfo = await checkSSHKeys();\n const sshConnection = sshInfo.exists ? await testSSHConnection() : { success: false };\n\n // Build auth method options\n const authOptions: Array<{ value: string; label: string; hint: string }> = [];\n\n if (sshInfo.exists && sshConnection.success) {\n authOptions.push({\n value: 'ssh-existing',\n label: 'Use existing SSH key',\n hint: `Connected as ${sshConnection.username}`,\n });\n }\n\n authOptions.push(\n {\n value: 'gh-cli',\n label: 'Install GitHub CLI (recommended)',\n hint: 'Easiest option - automatic repo creation',\n },\n {\n value: 'ssh-new',\n label: 'Set up SSH key',\n hint: sshInfo.exists ? 'Configure existing key' : 'Generate new SSH key',\n },\n {\n value: 'fine-grained',\n label: 'Use Fine-grained Token',\n hint: 'More secure - limited permissions',\n },\n {\n value: 'classic',\n label: 'Use Classic Token',\n hint: 'Broader access - simpler setup',\n },\n {\n value: 'skip',\n label: 'Skip for now',\n hint: 'Set up authentication later',\n }\n );\n\n const authMethod = await prompts.select('Choose an authentication method:', authOptions);\n\n if (authMethod === 'skip') {\n return { remoteUrl: null, pushed: false };\n }\n\n if (authMethod === 'gh-cli') {\n // Show GitHub CLI install instructions\n console.log();\n prompts.note(getGitHubCLIInstallInstructions(), 'GitHub CLI Installation');\n console.log();\n prompts.log.info('After installing and authenticating, run `tuck init` again');\n prompts.log.info('Or continue with token-based authentication below');\n\n const continueWithToken = await prompts.confirm('Set up token authentication instead?', true);\n if (!continueWithToken) {\n return { remoteUrl: null, pushed: false };\n }\n // Fall through to token setup\n return await setupTokenAuth(tuckDir);\n }\n\n if (authMethod === 'ssh-existing') {\n // SSH key already works - just need repo URL\n prompts.log.success(`SSH authenticated as ${sshConnection.username}`);\n return await promptForManualRepoUrl(tuckDir, sshConnection.username, 'ssh');\n }\n\n if (authMethod === 'ssh-new') {\n // Show SSH setup instructions\n console.log();\n prompts.note(getSSHKeyInstructions(), 'SSH Key Setup');\n console.log();\n\n if (sshInfo.exists) {\n prompts.log.info(`Found existing SSH key at ${sshInfo.path}`);\n if (sshInfo.publicKey) {\n console.log();\n prompts.log.info('Your public key (copy this to GitHub):');\n console.log(c.brand(sshInfo.publicKey));\n console.log();\n }\n }\n\n const sshReady = await prompts.confirm('Have you added your SSH key to GitHub?');\n if (sshReady) {\n // Test connection\n const testSpinner = prompts.spinner();\n testSpinner.start('Testing SSH connection...');\n const testResult = await testSSHConnection();\n if (testResult.success) {\n testSpinner.stop(`SSH authenticated as ${testResult.username}`);\n return await promptForManualRepoUrl(tuckDir, testResult.username, 'ssh');\n } else {\n testSpinner.stop('SSH connection failed');\n prompts.log.warning('Could not connect to GitHub via SSH');\n prompts.log.info('Make sure you added the public key and try again');\n\n const useTokenInstead = await prompts.confirm('Use token authentication instead?', true);\n if (useTokenInstead) {\n return await setupTokenAuth(tuckDir);\n }\n }\n }\n return { remoteUrl: null, pushed: false };\n }\n\n if (authMethod === 'fine-grained' || authMethod === 'classic') {\n return await setupTokenAuth(\n tuckDir,\n authMethod === 'fine-grained' ? 'fine-grained' : 'classic'\n );\n }\n\n return { remoteUrl: null, pushed: false };\n};\n\n/**\n * Set up token-based authentication\n */\nconst setupTokenAuth = async (\n tuckDir: string,\n preferredType?: 'fine-grained' | 'classic'\n): Promise<GitHubSetupResult> => {\n const tokenType =\n preferredType ??\n (await prompts.select('Which type of token?', [\n {\n value: 'fine-grained',\n label: 'Fine-grained Token (recommended)',\n hint: 'Limited permissions, more secure',\n },\n {\n value: 'classic',\n label: 'Classic Token',\n hint: 'Full repo access, simpler',\n },\n ]));\n\n // Show instructions for the selected token type\n console.log();\n if (tokenType === 'fine-grained') {\n prompts.note(getFineGrainedTokenInstructions(), 'Fine-grained Token Setup');\n } else {\n prompts.note(getClassicTokenInstructions(), 'Classic Token Setup');\n }\n console.log();\n\n // Ask for username\n const username = await prompts.text('Enter your GitHub username:', {\n validate: (value) => {\n if (!value) return 'Username is required';\n // GitHub username rules: 1-39 characters total, start with alphanumeric, may contain hyphens\n // (no consecutive or trailing hyphens).\n if (!/^[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}$/.test(value)) {\n return 'Invalid GitHub username (must start with a letter or number, be 1-39 characters, and may include hyphens but not consecutively or at the end).';\n }\n return undefined;\n },\n });\n\n // Ask for token\n const token = await prompts.password('Paste your token (hidden):');\n\n if (!token) {\n prompts.log.warning('No token provided');\n return { remoteUrl: null, pushed: false };\n }\n\n // Basic token format validation\n if (token.length < MIN_GITHUB_TOKEN_LENGTH) {\n prompts.log.error('Invalid token: Token appears too short');\n return { remoteUrl: null, pushed: false };\n }\n\n // Check if token starts with expected GitHub token prefixes\n const hasValidPrefix = GITHUB_TOKEN_PREFIXES.some((prefix) => token.startsWith(prefix));\n\n if (!hasValidPrefix) {\n const prefixList = GITHUB_TOKEN_PREFIXES.join(', ');\n prompts.log.warning(\n `Warning: Token does not start with a recognized GitHub prefix (${prefixList}). ` +\n 'This may cause authentication to fail.'\n );\n\n const proceedWithUnrecognizedToken = await prompts.confirm(\n 'The value you entered does not look like a typical GitHub personal access token. ' +\n 'Are you sure this is a GitHub token and not, for example, a password or another secret?'\n );\n\n if (!proceedWithUnrecognizedToken) {\n prompts.log.error(\n 'Aborting setup to avoid storing a value that may not be a GitHub token. ' +\n 'Please generate a GitHub personal access token and try again.'\n );\n return { remoteUrl: null, pushed: false };\n }\n }\n\n // Auto-detect token type\n const detectedType = detectTokenType(token);\n const finalType =\n detectedType !== 'unknown' ? detectedType : (tokenType as 'fine-grained' | 'classic');\n\n if (detectedType !== 'unknown' && detectedType !== tokenType) {\n prompts.log.info(\n `Detected ${detectedType === 'fine-grained' ? 'fine-grained' : 'classic'} token`\n );\n }\n\n // Store credentials securely\n const storeSpinner = prompts.spinner();\n storeSpinner.start('Storing credentials securely...');\n\n try {\n await storeGitHubCredentials(username, token, finalType);\n storeSpinner.stop('Credentials stored');\n prompts.log.success('Authentication configured successfully');\n } catch (error) {\n storeSpinner.stop('Failed to store credentials');\n prompts.log.warning(\n `Could not store credentials: ${error instanceof Error ? error.message : String(error)}`\n );\n prompts.log.info('You may be prompted for credentials when pushing');\n }\n\n // Configure git credential helper (best-effort; Git can still prompt for credentials if this fails)\n await configureGitCredentialHelper().catch((error) => {\n const errorMsg = error instanceof Error ? error.message : String(error);\n logger?.debug?.(`Failed to configure git credential helper (non-fatal): ${errorMsg}`);\n });\n\n return await promptForManualRepoUrl(tuckDir, username, 'https');\n};\n\n/**\n * Prompt user for a repository URL and configure remote\n */\nconst promptForManualRepoUrl = async (\n tuckDir: string,\n username?: string,\n preferredProtocol: 'ssh' | 'https' = 'https'\n): Promise<GitHubSetupResult> => {\n const suggestedName = 'dotfiles';\n const exampleUrl =\n preferredProtocol === 'ssh'\n ? `git@github.com:${username || 'username'}/${suggestedName}.git`\n : `https://github.com/${username || 'username'}/${suggestedName}.git`;\n\n console.log();\n prompts.note(\n `Create a repository on GitHub:\\n\\n` +\n `1. Go to: https://github.com/new\\n` +\n `2. Name: ${suggestedName}\\n` +\n `3. Visibility: Private (recommended)\\n` +\n `4. Do NOT add README or .gitignore\\n` +\n `5. Click \"Create repository\"\\n` +\n `6. Copy the ${preferredProtocol.toUpperCase()} URL`,\n 'Manual Repository Setup'\n );\n console.log();\n\n const hasRepo = await prompts.confirm('Have you created the repository?');\n if (!hasRepo) {\n prompts.log.info('Create a repository first, then run `tuck init` again');\n return { remoteUrl: null, pushed: false };\n }\n\n const repoUrl = await prompts.text('Paste the repository URL:', {\n placeholder: exampleUrl,\n validate: validateGitHubUrl,\n });\n\n // Add remote\n try {\n await addRemote(tuckDir, 'origin', repoUrl);\n prompts.log.success('Remote configured');\n return { remoteUrl: repoUrl, pushed: false };\n } catch (error) {\n prompts.log.error(\n `Failed to add remote: ${error instanceof Error ? error.message : String(error)}`\n );\n return { remoteUrl: null, pushed: false };\n }\n};\n\nconst setupGitHubRepo = async (tuckDir: string): Promise<GitHubSetupResult> => {\n // Check if GitHub CLI is available\n const ghInstalled = await isGhInstalled();\n if (!ghInstalled) {\n // Offer alternative authentication methods\n return await setupAlternativeAuth(tuckDir);\n }\n\n const ghAuth = await isGhAuthenticated();\n if (!ghAuth) {\n prompts.log.info('GitHub CLI is installed but not authenticated');\n\n const authChoice = await prompts.select('How would you like to authenticate?', [\n {\n value: 'gh-login',\n label: 'Run `gh auth login` now',\n hint: 'Opens browser to authenticate',\n },\n {\n value: 'alternative',\n label: 'Use alternative method',\n hint: 'SSH key or personal access token',\n },\n {\n value: 'skip',\n label: 'Skip for now',\n hint: 'Set up authentication later',\n },\n ]);\n\n if (authChoice === 'skip') {\n return { remoteUrl: null, pushed: false };\n }\n\n if (authChoice === 'alternative') {\n return await setupAlternativeAuth(tuckDir);\n }\n\n // Run gh auth login\n prompts.log.info('Please complete the authentication in your browser...');\n try {\n const { execFile } = await import('child_process');\n const { promisify } = await import('util');\n const execFileAsync = promisify(execFile);\n await execFileAsync('gh', ['auth', 'login', '--web']);\n\n // Re-check auth status\n if (!(await isGhAuthenticated())) {\n prompts.log.warning('Authentication may have failed');\n return await setupAlternativeAuth(tuckDir);\n }\n } catch (error) {\n prompts.log.warning(\n `Authentication failed: ${error instanceof Error ? error.message : String(error)}`\n );\n const useAlt = await prompts.confirm('Try alternative authentication?', true);\n if (useAlt) {\n return await setupAlternativeAuth(tuckDir);\n }\n return { remoteUrl: null, pushed: false };\n }\n }\n\n // Get authenticated user\n const user = await getAuthenticatedUser();\n prompts.log.success(`Detected GitHub account: ${user.login}`);\n\n // Ask if they want to auto-create repo\n const createGhRepo = await prompts.confirm('Create a GitHub repository automatically?', true);\n\n if (!createGhRepo) {\n return { remoteUrl: null, pushed: false };\n }\n\n // Ask for repo name\n const repoName = await prompts.text('Repository name:', {\n defaultValue: 'dotfiles',\n placeholder: 'dotfiles',\n validate: (value) => {\n if (!value) return 'Repository name is required';\n if (!/^[a-zA-Z0-9._-]+$/.test(value)) {\n return 'Invalid repository name';\n }\n return undefined;\n },\n });\n\n // Ask for visibility\n const visibility = await prompts.select('Repository visibility:', [\n { value: 'private', label: 'Private (recommended)', hint: 'Only you can see it' },\n { value: 'public', label: 'Public', hint: 'Anyone can see it' },\n ]);\n\n // Create the repository\n let repo;\n try {\n const spinner = prompts.spinner();\n spinner.start(`Creating repository ${user.login}/${repoName}...`);\n\n repo = await createRepo({\n name: repoName,\n description: 'My dotfiles managed with tuck',\n isPrivate: visibility === 'private',\n });\n\n spinner.stop(`Repository created: ${repo.fullName}`);\n } catch (error) {\n prompts.log.error(\n `Failed to create repository: ${error instanceof Error ? error.message : String(error)}`\n );\n return { remoteUrl: null, pushed: false };\n }\n\n // Get the remote URL in preferred format\n const remoteUrl = await getPreferredRepoUrl(repo);\n\n // Add as remote\n await addRemote(tuckDir, 'origin', remoteUrl);\n prompts.log.success('Remote origin configured');\n\n // Ask to push initial commit\n const shouldPush = await prompts.confirm('Push initial commit to GitHub?', true);\n\n if (shouldPush) {\n try {\n const spinner = prompts.spinner();\n spinner.start('Creating initial commit...');\n\n await stageAll(tuckDir);\n await commit(tuckDir, 'Initial commit: tuck dotfiles setup');\n\n spinner.stop('Initial commit created');\n\n spinner.start('Pushing to GitHub...');\n await push(tuckDir, { remote: 'origin', branch: 'main', setUpstream: true });\n spinner.stop('Pushed to GitHub');\n\n prompts.note(\n `Your dotfiles are now at:\\n${repo.url}\\n\\nOn a new machine, run:\\ntuck apply ${user.login}`,\n 'Success'\n );\n\n return { remoteUrl, pushed: true };\n } catch (error) {\n prompts.log.error(\n `Failed to push: ${error instanceof Error ? error.message : String(error)}`\n );\n return { remoteUrl, pushed: false };\n }\n }\n\n return { remoteUrl, pushed: false };\n};\n\ntype RepositoryAnalysis =\n | { type: 'valid-tuck'; manifest: TuckManifest }\n | { type: 'plain-dotfiles'; files: DetectedFile[] }\n | { type: 'messed-up'; reason: string };\n\n/**\n * Analyze a cloned repository to determine its state\n */\nconst analyzeRepository = async (repoDir: string): Promise<RepositoryAnalysis> => {\n const manifestPath = join(repoDir, '.tuckmanifest.json');\n\n // Check for valid tuck manifest\n if (await pathExists(manifestPath)) {\n try {\n const content = await readFile(manifestPath, 'utf-8');\n const manifest = JSON.parse(content) as TuckManifest;\n\n // Validate manifest has files\n if (manifest.files && Object.keys(manifest.files).length > 0) {\n return { type: 'valid-tuck', manifest };\n }\n\n // Manifest exists but is empty\n return { type: 'messed-up', reason: 'Manifest exists but contains no tracked files' };\n } catch {\n return { type: 'messed-up', reason: 'Manifest file is corrupted or invalid' };\n }\n }\n\n // No manifest - check for common dotfiles in the files directory or root\n const filesDir = join(repoDir, 'files');\n const hasFilesDir = await pathExists(filesDir);\n\n // Look for common dotfile patterns in the repo\n const commonPatterns = [\n '.zshrc',\n '.bashrc',\n '.bash_profile',\n '.gitconfig',\n '.vimrc',\n '.tmux.conf',\n '.profile',\n 'zshrc',\n 'bashrc',\n 'gitconfig',\n 'vimrc',\n ];\n\n const foundFiles: string[] = [];\n\n // Check in files directory if it exists\n if (hasFilesDir) {\n const { readdir } = await import('fs/promises');\n try {\n const categories = await readdir(filesDir);\n for (const category of categories) {\n const categoryPath = join(filesDir, category);\n const categoryStats = await import('fs/promises').then((fs) =>\n fs.stat(categoryPath).catch(() => null)\n );\n if (categoryStats?.isDirectory()) {\n const files = await readdir(categoryPath);\n foundFiles.push(...files);\n }\n }\n } catch {\n // Ignore errors\n }\n }\n\n // Check root directory\n const { readdir } = await import('fs/promises');\n try {\n const rootFiles = await readdir(repoDir);\n for (const file of rootFiles) {\n if (commonPatterns.some((p) => file.includes(p) || file.startsWith('.'))) {\n foundFiles.push(file);\n }\n }\n } catch {\n // Ignore errors\n }\n\n // Filter to meaningful dotfiles (not just .git, README, etc.)\n const meaningfulFiles = foundFiles.filter(\n (f) => !['README.md', 'README', '.git', '.gitignore', 'LICENSE', '.tuckrc.json'].includes(f)\n );\n\n if (meaningfulFiles.length > 0) {\n // Run detection on user's system and show what would be tracked\n const detectedOnSystem = await detectDotfiles();\n return { type: 'plain-dotfiles', files: detectedOnSystem };\n }\n\n // Check if repo is essentially empty (only has README, .git, etc.)\n const { readdir: rd } = await import('fs/promises');\n try {\n const allFiles = await rd(repoDir);\n const nonEssentialFiles = allFiles.filter(\n (f) => !['.git', 'README.md', 'README', 'LICENSE', '.gitignore'].includes(f)\n );\n if (nonEssentialFiles.length === 0) {\n return { type: 'messed-up', reason: 'Repository is empty (only contains README or license)' };\n }\n } catch {\n // Ignore\n }\n\n return { type: 'messed-up', reason: 'Repository does not contain recognizable dotfiles' };\n};\n\ninterface ImportResult {\n success: boolean;\n filesInRepo: number; // Files imported to ~/.tuck\n filesApplied: number; // Files applied to system (0 if user declined)\n remoteUrl?: string;\n}\n\n/**\n * Import an existing GitHub dotfiles repository\n */\nconst importExistingRepo = async (\n tuckDir: string,\n repoName: string,\n analysis: RepositoryAnalysis,\n repoDir: string\n): Promise<ImportResult> => {\n const { getPreferredRemoteProtocol } = await import('../lib/github.js');\n const protocol = await getPreferredRemoteProtocol();\n const remoteUrl =\n protocol === 'ssh' ? `git@github.com:${repoName}.git` : `https://github.com/${repoName}.git`;\n\n if (analysis.type === 'valid-tuck') {\n // Scenario A: Valid tuck repository - import only (NO auto-apply)\n // BREAKING CHANGE: Files are no longer automatically applied when cloning a tuck repository.\n // This is a safer default that prevents accidental overwrites of existing configurations.\n // User should run 'tuck apply' or 'tuck restore' manually when ready.\n prompts.log.step('Importing tuck repository...');\n\n // Copy the entire repo to tuck directory\n const spinner = prompts.spinner();\n spinner.start('Copying repository...');\n\n // Copy files from cloned repo to tuck directory\n await copy(repoDir, tuckDir, { overwrite: true });\n\n spinner.stop('Repository imported');\n\n // Get file count and group by category for display\n const fileCount = Object.keys(analysis.manifest.files).length;\n\n // Group files by category\n const grouped: Record<string, string[]> = {};\n for (const [_id, file] of Object.entries(analysis.manifest.files)) {\n if (!grouped[file.category]) grouped[file.category] = [];\n grouped[file.category].push(file.source);\n }\n\n // Display what's available\n console.log();\n prompts.log.success(`Imported ${fileCount} dotfiles to ~/.tuck`);\n console.log();\n\n // Show files by category with icons\n const { DETECTION_CATEGORIES } = await import('../lib/detect.js');\n for (const [category, files] of Object.entries(grouped)) {\n const categoryInfo = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n console.log(\n c.brand(\n ` ${categoryInfo.icon} ${categoryInfo.name}: ${files.length} file${files.length > 1 ? 's' : ''}`\n )\n );\n }\n\n console.log();\n prompts.note(\n 'Your dotfiles are now in ~/.tuck but NOT applied to your system.\\n\\n' +\n 'To apply them to your system, run:\\n' +\n ' tuck apply # Interactive with merge options\\n' +\n ' tuck restore # Simple restore from backup\\n\\n' +\n 'To see what files are available:\\n' +\n ' tuck list',\n 'Next Steps'\n );\n\n // filesApplied is always 0 - user must explicitly apply via tuck apply/restore\n return { success: true, filesInRepo: fileCount, filesApplied: 0, remoteUrl };\n }\n\n if (analysis.type === 'plain-dotfiles') {\n // Scenario B: Plain dotfiles repository - copy contents and initialize tuck\n prompts.log.step('Repository contains dotfiles but no tuck manifest');\n prompts.log.info('Importing repository and setting up tuck...');\n\n // Copy the repository contents to tuck directory first (preserving existing files)\n const copySpinner = prompts.spinner();\n copySpinner.start('Copying repository contents...');\n await copy(repoDir, tuckDir, { overwrite: true });\n copySpinner.stop('Repository contents copied');\n\n // Now initialize git and create tuck config on top of the copied files\n // Note: The .git directory was copied, so we don't need to reinitialize\n await setDefaultBranch(tuckDir, 'main');\n\n const hostname = (await import('os')).hostname();\n await createManifest(tuckDir, hostname);\n await saveConfig(\n {\n ...defaultConfig,\n repository: { ...defaultConfig.repository, path: tuckDir },\n },\n tuckDir\n );\n\n // Create directory structure for categories (if not already present)\n await createDirectoryStructure(tuckDir);\n await createDefaultFiles(tuckDir, hostname);\n\n // Update remote to use the correct URL (may differ from cloned URL)\n try {\n // Remove existing origin if present and add the correct one\n const { removeRemote } = await import('../lib/git.js');\n await removeRemote(tuckDir, 'origin').catch(() => {\n /* ignore if not exists */\n });\n await addRemote(tuckDir, 'origin', remoteUrl);\n } catch {\n // If removing fails, try adding anyway\n await addRemote(tuckDir, 'origin', remoteUrl).catch(() => {\n /* ignore if already exists */\n });\n }\n\n // Detect dotfiles on system that could be tracked\n const detected = analysis.files.filter((f) => !f.sensitive);\n\n console.log();\n prompts.log.success('Repository imported to ~/.tuck');\n prompts.log.info(\"The repository's files are now in your tuck directory.\");\n\n if (detected.length > 0) {\n console.log();\n prompts.log.info(`Found ${detected.length} dotfiles on your system that could be tracked`);\n\n const trackNow = await prompts.confirm('Would you like to add some of these to tuck?', true);\n\n if (trackNow) {\n // Group by category for display\n const grouped: Record<string, DetectedFile[]> = {};\n for (const file of detected) {\n if (!grouped[file.category]) grouped[file.category] = [];\n grouped[file.category].push(file);\n }\n\n // Show categories\n console.log();\n for (const [category, files] of Object.entries(grouped)) {\n const config = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n console.log(` ${config.icon} ${config.name}: ${files.length} files`);\n }\n\n console.log();\n prompts.log.info(\"Run 'tuck scan' to interactively select files to track\");\n prompts.log.info(\"Or run 'tuck add <path>' to add specific files\");\n }\n }\n\n // Count the files that were copied (excluding .git and tuck config files)\n let importedCount = 0;\n const { readdir, stat } = await import('fs/promises');\n try {\n const countFiles = async (dir: string): Promise<number> => {\n let count = 0;\n const entries = await readdir(dir);\n for (const entry of entries) {\n if (entry === '.git' || entry === '.tuckmanifest.json' || entry === '.tuckrc.json')\n continue;\n const fullPath = join(dir, entry);\n const stats = await stat(fullPath).catch(() => null);\n if (stats?.isDirectory()) {\n count += await countFiles(fullPath);\n } else if (stats?.isFile()) {\n count++;\n }\n }\n return count;\n };\n importedCount = await countFiles(tuckDir);\n } catch {\n // Ignore counting errors\n }\n\n // For plain-dotfiles, importedCount represents files copied to ~/.tuck\n // No files are applied to system in this flow (user needs to add them manually)\n return { success: true, filesInRepo: importedCount, filesApplied: 0, remoteUrl };\n }\n\n // Scenario C: Messed up repository\n prompts.log.warning(`Repository issue: ${analysis.reason}`);\n console.log();\n\n const action = await prompts.select('How would you like to proceed?', [\n {\n value: 'fresh',\n label: 'Start fresh',\n hint: 'Initialize tuck and set this repo as remote (will overwrite on push)',\n },\n {\n value: 'remote-only',\n label: 'Set as remote only',\n hint: 'Initialize tuck locally, keep existing repo contents',\n },\n {\n value: 'cancel',\n label: 'Cancel',\n hint: 'Inspect the repository manually first',\n },\n ]);\n\n if (action === 'cancel') {\n return { success: false, filesInRepo: 0, filesApplied: 0 };\n }\n\n // Initialize tuck\n await createDirectoryStructure(tuckDir);\n await initRepo(tuckDir);\n await setDefaultBranch(tuckDir, 'main');\n\n const hostname = (await import('os')).hostname();\n await createManifest(tuckDir, hostname);\n await saveConfig(\n {\n ...defaultConfig,\n repository: { ...defaultConfig.repository, path: tuckDir },\n },\n tuckDir\n );\n await createDefaultFiles(tuckDir, hostname);\n\n // Set up remote\n await addRemote(tuckDir, 'origin', remoteUrl);\n\n if (action === 'fresh') {\n prompts.log.info('Tuck initialized. When you push, it will replace the repository contents.');\n prompts.log.info(\n \"Run 'tuck add' to track files, then 'tuck sync && tuck push --force' to update remote\"\n );\n } else {\n prompts.log.info('Tuck initialized with remote configured');\n prompts.log.info(\"Run 'tuck add' to start tracking files\");\n }\n\n // For messed-up repos, no files are imported or applied\n return { success: true, filesInRepo: 0, filesApplied: 0, remoteUrl };\n};\n\nconst initFromRemote = async (tuckDir: string, remoteUrl: string): Promise<void> => {\n // Clone the repository\n await withSpinner(`Cloning from ${remoteUrl}...`, async () => {\n await cloneRepo(remoteUrl, tuckDir);\n });\n\n // Verify manifest exists\n if (!(await pathExists(getManifestPath(tuckDir)))) {\n logger.warning('No manifest found in cloned repository. Creating new manifest...');\n const hostname = (await import('os')).hostname();\n await createManifest(tuckDir, hostname);\n }\n\n // Verify config exists\n if (!(await pathExists(getConfigPath(tuckDir)))) {\n logger.warning('No config found in cloned repository. Creating default config...');\n await saveConfig(\n {\n ...defaultConfig,\n repository: { ...defaultConfig.repository, path: tuckDir },\n },\n tuckDir\n );\n }\n};\n\nconst runInteractiveInit = async (): Promise<void> => {\n banner();\n prompts.intro('tuck init');\n\n // Ask for tuck directory\n const dirInput = await prompts.text('Where should tuck store your dotfiles?', {\n defaultValue: '~/.tuck',\n });\n const tuckDir = getTuckDir(dirInput);\n\n // Check if already initialized\n if (await pathExists(getManifestPath(tuckDir))) {\n prompts.log.error(`Tuck is already initialized at ${collapsePath(tuckDir)}`);\n prompts.outro('Use `tuck status` to see current state');\n return;\n }\n\n // Flow control flags\n let skipExistingRepoQuestion = false;\n let remoteUrl: string | null = null;\n let existingRepoToUseAsRemote: string | null = null;\n\n // Auto-detect existing GitHub dotfiles repository\n const ghInstalled = await isGhInstalled();\n const ghAuth = ghInstalled && (await isGhAuthenticated());\n\n if (ghAuth) {\n const spinner = prompts.spinner();\n spinner.start('Checking for existing dotfiles repository on GitHub...');\n\n try {\n const user = await getAuthenticatedUser();\n const existingRepoName = await findDotfilesRepo(user.login);\n\n if (existingRepoName) {\n spinner.stop(`Found repository: ${existingRepoName}`);\n\n const importRepo = await prompts.confirm(`Import dotfiles from ${existingRepoName}?`, true);\n\n if (importRepo) {\n // Clone to temp directory\n const tempDir = join(tmpdir(), `tuck-import-${Date.now()}`);\n const cloneSpinner = prompts.spinner();\n cloneSpinner.start('Cloning repository...');\n let phase: 'cloning' | 'analyzing' | 'importing' = 'cloning';\n\n try {\n await ghCloneRepo(existingRepoName, tempDir);\n cloneSpinner.stop('Repository cloned');\n phase = 'analyzing';\n\n // Analyze the repository\n const analysisSpinner = prompts.spinner();\n analysisSpinner.start('Analyzing repository...');\n let analysis: RepositoryAnalysis;\n try {\n analysis = await analyzeRepository(tempDir);\n analysisSpinner.stop('Analysis complete');\n } catch (error) {\n analysisSpinner.stop('Analysis failed');\n throw new Error(\n `Failed to analyze repository: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n phase = 'importing';\n // Import based on analysis\n const result = await importExistingRepo(tuckDir, existingRepoName, analysis, tempDir);\n\n if (result.success) {\n console.log();\n // Always show that repository was imported to ~/.tuck\n if (result.filesInRepo > 0) {\n prompts.log.success(`Repository imported to ~/.tuck (${result.filesInRepo} files)`);\n if (result.filesApplied > 0) {\n prompts.log.info(`Applied ${result.filesApplied} files to your system`);\n } else if (result.filesInRepo > 0) {\n prompts.log.info(\n 'Files are ready in ~/.tuck. Run \"tuck restore\" to apply them to your system'\n );\n }\n } else {\n prompts.log.success(`Tuck initialized with ${existingRepoName} as remote`);\n }\n\n prompts.outro('Ready to manage your dotfiles!');\n\n nextSteps([\n `View status: tuck status`,\n `Add files: tuck add ~/.zshrc`,\n `Sync: tuck sync`,\n ]);\n return;\n }\n\n // User cancelled - continue with normal flow\n console.log();\n } catch (error) {\n // Only stop clone spinner if we're still in cloning phase\n if (phase === 'cloning') {\n cloneSpinner.stop('Clone failed');\n }\n\n // Provide accurate error messages based on which phase failed\n const errorMessage = error instanceof Error ? error.message : String(error);\n if (phase === 'analyzing') {\n prompts.log.warning(errorMessage);\n } else if (phase === 'importing') {\n prompts.log.warning(errorMessage);\n } else {\n prompts.log.warning(`Could not clone repository: ${errorMessage}`);\n }\n console.log();\n\n // Offer to use the failed repo as remote and continue with fresh init\n const useAsRemoteAnyway = await prompts.confirm(\n `Use ${existingRepoName} as your remote and start fresh?`,\n true\n );\n\n if (useAsRemoteAnyway) {\n existingRepoToUseAsRemote = existingRepoName;\n skipExistingRepoQuestion = true;\n }\n } finally {\n // Always clean up temp directory if it exists\n if (await pathExists(tempDir)) {\n try {\n await rm(tempDir, { recursive: true, force: true });\n } catch (cleanupError) {\n // Log but don't throw - cleanup failure shouldn't break the flow\n prompts.log.warning(\n `Failed to clean up temporary directory: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`\n );\n }\n }\n }\n } else {\n // User declined to import - offer to use as remote only\n console.log();\n const useAsRemote = await prompts.confirm(\n `Use ${existingRepoName} as your remote (without importing its contents)?`,\n true\n );\n\n if (useAsRemote) {\n existingRepoToUseAsRemote = existingRepoName;\n }\n skipExistingRepoQuestion = true;\n }\n } else {\n spinner.stop('No existing dotfiles repository found');\n }\n } catch {\n spinner.stop('Could not check for existing repositories');\n }\n }\n\n // Ask about existing repo (manual flow) - skip if we already handled it\n if (!skipExistingRepoQuestion) {\n const hasExisting = await prompts.select('Do you have an existing dotfiles repository?', [\n { value: 'no', label: 'No, start fresh' },\n { value: 'yes', label: 'Yes, clone from URL' },\n ]);\n\n if (hasExisting === 'yes') {\n const repoUrl = await prompts.text('Enter repository URL:', {\n placeholder: 'git@host:user/dotfiles.git or https://host/user/dotfiles.git',\n validate: validateGitUrl,\n });\n\n await initFromRemote(tuckDir, repoUrl);\n\n prompts.log.success('Repository cloned successfully!');\n\n const shouldRestore = await prompts.confirm('Would you like to restore dotfiles now?', true);\n\n if (shouldRestore) {\n console.log();\n // Dynamically import and run restore\n const { runRestore } = await import('./restore.js');\n await runRestore({ all: true });\n }\n\n prompts.outro('Tuck initialized successfully!');\n nextSteps([\n `View status: tuck status`,\n `Add files: tuck add ~/.zshrc`,\n `Sync: tuck sync`,\n ]);\n return;\n }\n }\n\n // Initialize from scratch\n await initFromScratch(tuckDir, {});\n\n // If we have an existing repo to use as remote, set it up now\n if (existingRepoToUseAsRemote) {\n const protocol = await getPreferredRemoteProtocol();\n remoteUrl =\n protocol === 'ssh'\n ? `git@github.com:${existingRepoToUseAsRemote}.git`\n : `https://github.com/${existingRepoToUseAsRemote}.git`;\n\n await addRemote(tuckDir, 'origin', remoteUrl);\n prompts.log.success(`Remote set to ${existingRepoToUseAsRemote}`);\n prompts.log.info('Your next push will update the remote repository');\n console.log();\n }\n\n // ========== STEP 1: Remote Setup (if not already configured) ==========\n if (!remoteUrl) {\n const wantsRemote = await prompts.confirm(\n 'Would you like to set up a remote repository?',\n true\n );\n\n if (wantsRemote) {\n // Try GitHub auto-setup\n const ghResult = await setupGitHubRepo(tuckDir);\n remoteUrl = ghResult.remoteUrl;\n\n // If GitHub setup didn't add a remote, show manual instructions\n if (!ghResult.remoteUrl) {\n // Get user info for examples\n const user = await getAuthenticatedUser().catch(() => null);\n const suggestedName = 'dotfiles';\n\n console.log();\n prompts.note(\n `To create a GitHub repository manually:\\n\\n` +\n `1. Go to: https://github.com/new\\n` +\n `2. Repository name: ${suggestedName}\\n` +\n `3. Description: My dotfiles managed with tuck\\n` +\n `4. Visibility: Private (recommended)\\n` +\n `5. IMPORTANT: Do NOT initialize with:\\n` +\n ` - NO README\\n` +\n ` - NO .gitignore\\n` +\n ` - NO license\\n` +\n `6. Click \"Create repository\"\\n` +\n `7. Copy the URL shown\\n\\n` +\n `Example URLs:\\n` +\n ` SSH: git@github.com:${user?.login || 'username'}/${suggestedName}.git\\n` +\n ` HTTPS: https://github.com/${user?.login || 'username'}/${suggestedName}.git`,\n 'Manual Repository Setup'\n );\n console.log();\n\n const useManual = await prompts.confirm('Did you create a GitHub repository?', true);\n\n if (useManual) {\n const manualUrl = await prompts.text('Paste your GitHub repository URL:', {\n placeholder: `git@github.com:${user?.login || 'user'}/${suggestedName}.git`,\n validate: validateGitHubUrl,\n });\n\n if (manualUrl) {\n await addRemote(tuckDir, 'origin', manualUrl);\n prompts.log.success('Remote added successfully');\n remoteUrl = manualUrl;\n }\n }\n }\n }\n }\n\n // ========== STEP 2: Detect and Select Files ==========\n const scanSpinner = prompts.spinner();\n scanSpinner.start('Scanning for dotfiles...');\n const detectedFiles = await detectDotfiles();\n const nonSensitiveFiles = detectedFiles.filter((f) => !f.sensitive);\n const sensitiveFiles = detectedFiles.filter((f) => f.sensitive);\n scanSpinner.stop(`Found ${detectedFiles.length} dotfiles on your system`);\n\n let trackedCount = 0;\n\n // Handle non-sensitive files\n if (nonSensitiveFiles.length > 0) {\n // Group by category and show summary\n const grouped: Record<string, DetectedFile[]> = {};\n for (const file of nonSensitiveFiles) {\n if (!grouped[file.category]) grouped[file.category] = [];\n grouped[file.category].push(file);\n }\n\n console.log();\n const categoryOrder = ['shell', 'git', 'editors', 'terminal', 'ssh', 'misc'];\n const sortedCategories = Object.keys(grouped).sort((a, b) => {\n const aIdx = categoryOrder.indexOf(a);\n const bIdx = categoryOrder.indexOf(b);\n if (aIdx === -1 && bIdx === -1) return a.localeCompare(b);\n if (aIdx === -1) return 1;\n if (bIdx === -1) return -1;\n return aIdx - bIdx;\n });\n\n for (const category of sortedCategories) {\n const files = grouped[category];\n const config = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n console.log(` ${config.icon} ${config.name}: ${files.length} files`);\n }\n console.log();\n\n const trackNow = await prompts.confirm('Would you like to track some of these now?', true);\n\n if (trackNow) {\n // Show multiselect with all files PRE-SELECTED by default\n const options = nonSensitiveFiles.map((f) => ({\n value: f.path,\n label: `${collapsePath(f.path)}`,\n hint: f.category,\n }));\n\n // Pre-select all non-sensitive files\n const initialValues = nonSensitiveFiles.map((f) => f.path);\n\n const selectedFiles = await prompts.multiselect(\n 'Select files to track (all pre-selected; use space to toggle selection):',\n options,\n { initialValues }\n );\n\n // Handle sensitive files with individual prompts\n const filesToTrack = [...selectedFiles];\n\n if (sensitiveFiles.length > 0) {\n console.log();\n prompts.log.warning(`Found ${sensitiveFiles.length} sensitive file(s):`);\n\n for (const sf of sensitiveFiles) {\n console.log(c.warning(` ! ${collapsePath(sf.path)} - ${sf.description || sf.category}`));\n }\n\n console.log();\n const trackSensitive = await prompts.confirm(\n 'Would you like to review sensitive files? (Ensure your repo is PRIVATE)',\n false\n );\n\n if (trackSensitive) {\n for (const sf of sensitiveFiles) {\n const track = await prompts.confirm(`Track ${collapsePath(sf.path)}?`, false);\n if (track) {\n filesToTrack.push(sf.path);\n }\n }\n }\n }\n\n if (filesToTrack.length > 0) {\n // Track files with beautiful progress display\n trackedCount = await trackFilesWithProgressInit(filesToTrack, tuckDir);\n }\n } else {\n prompts.log.info(\"Run 'tuck scan' later to interactively add files\");\n }\n }\n\n // Handle case where only sensitive files were found\n if (nonSensitiveFiles.length === 0 && sensitiveFiles.length > 0) {\n console.log();\n prompts.log.warning(`Found ${sensitiveFiles.length} sensitive file(s):`);\n\n for (const sf of sensitiveFiles) {\n console.log(c.warning(` ! ${collapsePath(sf.path)} - ${sf.description || sf.category}`));\n }\n\n console.log();\n const trackSensitive = await prompts.confirm(\n 'Would you like to review these sensitive files? (Ensure your repo is PRIVATE)',\n false\n );\n\n if (trackSensitive) {\n const filesToTrack: string[] = [];\n for (const sf of sensitiveFiles) {\n const track = await prompts.confirm(`Track ${collapsePath(sf.path)}?`, false);\n if (track) {\n filesToTrack.push(sf.path);\n }\n }\n\n if (filesToTrack.length > 0) {\n // Track files with beautiful progress display\n trackedCount = await trackFilesWithProgressInit(filesToTrack, tuckDir);\n }\n } else {\n prompts.log.info(\"Run 'tuck scan' later to interactively add files\");\n }\n }\n\n // Handle case where no files were found\n if (detectedFiles.length === 0) {\n console.log();\n prompts.log.info('No dotfiles detected on your system');\n prompts.log.info(\"Run 'tuck add <path>' to manually track files\");\n }\n\n // ========== STEP 3: Commit and Push ==========\n if (trackedCount > 0) {\n console.log();\n\n if (remoteUrl) {\n // Remote is configured - offer to commit AND push\n const action = await prompts.select('Your files are tracked. What would you like to do?', [\n {\n value: 'commit-push',\n label: 'Commit and push to remote',\n hint: 'Recommended - sync your dotfiles now',\n },\n {\n value: 'commit-only',\n label: 'Commit only',\n hint: \"Save locally, push later with 'tuck push'\",\n },\n {\n value: 'skip',\n label: 'Skip for now',\n hint: \"Run 'tuck sync' later\",\n },\n ]);\n\n if (action !== 'skip') {\n const commitSpinner = prompts.spinner();\n commitSpinner.start('Committing changes...');\n\n await stageAll(tuckDir);\n const commitHash = await commit(tuckDir, `Add ${trackedCount} dotfiles via tuck init`);\n\n commitSpinner.stop(`Committed: ${commitHash.slice(0, 7)}`);\n\n if (action === 'commit-push') {\n const pushSpinner = prompts.spinner();\n pushSpinner.start('Pushing to remote...');\n\n try {\n await push(tuckDir, { remote: 'origin', branch: 'main', setUpstream: true });\n pushSpinner.stop('Pushed successfully!');\n\n // Show success with URL\n let viewUrl = remoteUrl;\n if (viewUrl.startsWith('git@github.com:')) {\n viewUrl = viewUrl\n .replace('git@github.com:', 'https://github.com/')\n .replace('.git', '');\n } else if (viewUrl.startsWith('https://github.com/')) {\n viewUrl = viewUrl.replace('.git', '');\n }\n\n console.log();\n prompts.note(\n `Your dotfiles are now live at:\\n${viewUrl}\\n\\n` +\n `On a new machine, run:\\n tuck init --from ${viewUrl}`,\n 'Success!'\n );\n } catch (error) {\n pushSpinner.stop('Push failed');\n const errorMsg = error instanceof Error ? error.message : String(error);\n prompts.log.warning(`Could not push: ${errorMsg}`);\n prompts.log.info(\"Run 'tuck push' to try again\");\n }\n } else {\n prompts.log.info(\"Run 'tuck push' when you're ready to upload to remote\");\n }\n }\n } else {\n // No remote configured\n const shouldCommit = await prompts.confirm('Commit these changes locally?', true);\n\n if (shouldCommit) {\n const commitSpinner = prompts.spinner();\n commitSpinner.start('Committing...');\n\n await stageAll(tuckDir);\n const commitHash = await commit(tuckDir, `Add ${trackedCount} dotfiles via tuck init`);\n\n commitSpinner.stop(`Committed: ${commitHash.slice(0, 7)}`);\n prompts.log.info(\"Set up a remote with 'tuck push' to backup your dotfiles\");\n }\n }\n }\n\n prompts.outro('Tuck initialized successfully!');\n\n nextSteps([\n `View status: tuck status`,\n `Add files: tuck add ~/.zshrc`,\n `Sync: tuck sync`,\n ]);\n};\n\nconst runInit = async (options: InitOptions): Promise<void> => {\n const tuckDir = getTuckDir(options.dir);\n\n // If --from is provided, clone from remote\n if (options.from) {\n await initFromRemote(tuckDir, options.from);\n logger.success(`Tuck initialized from ${options.from}`);\n logger.info('Run `tuck restore --all` to restore dotfiles');\n return;\n }\n\n // Initialize from scratch\n await initFromScratch(tuckDir, {\n remote: options.remote,\n bare: options.bare,\n });\n\n logger.success(`Tuck initialized at ${collapsePath(tuckDir)}`);\n\n nextSteps([\n `Add files: tuck add ~/.zshrc`,\n `Sync changes: tuck sync`,\n `Push remote: tuck push`,\n ]);\n};\n\nexport const initCommand = new Command('init')\n .description('Initialize tuck repository')\n .option('-d, --dir <path>', 'Directory for tuck repository', '~/.tuck')\n .option('-r, --remote <url>', 'Git remote URL to set up')\n .option('--bare', 'Initialize without any default files')\n .option('--from <url>', 'Clone from existing tuck repository')\n .action(async (options: InitOptions) => {\n // If no options provided, run interactive mode\n if (!options.remote && !options.bare && !options.from && options.dir === '~/.tuck') {\n await runInteractiveInit();\n } else {\n await runInit(options);\n }\n });\n","import { Command } from 'commander';\nimport { basename } from 'path';\nimport { prompts, logger, colors as c } from '../ui/index.js';\nimport {\n getTuckDir,\n expandPath,\n collapsePath,\n pathExists,\n isDirectory,\n detectCategory,\n sanitizeFilename,\n getDestinationPath,\n} from '../lib/paths.js';\nimport { isFileTracked, loadManifest } from '../lib/manifest.js';\nimport { trackFilesWithProgress, type FileToTrack } from '../lib/fileTracking.js';\nimport {\n NotInitializedError,\n FileNotFoundError,\n FileAlreadyTrackedError,\n SecretsDetectedError,\n} from '../errors.js';\nimport { CATEGORIES } from '../constants.js';\nimport type { AddOptions } from '../types.js';\nimport { getDirectoryFileCount, checkFileSizeThreshold, formatFileSize } from '../lib/files.js';\nimport { shouldExcludeFromBin } from '../lib/binary.js';\nimport { addToTuckignore, isIgnored } from '../lib/tuckignore.js';\nimport { loadConfig } from '../lib/config.js';\nimport {\n scanForSecrets,\n processSecretsForRedaction,\n redactFile,\n getSecretsPath,\n type ScanSummary,\n} from '../lib/secrets/index.js';\n\n// SSH private key patterns - NEVER allow these\nconst PRIVATE_KEY_PATTERNS = [\n /^id_rsa$/,\n /^id_dsa$/,\n /^id_ecdsa$/,\n /^id_ed25519$/,\n /^id_.*$/, // Any id_ file without .pub\n /\\.pem$/,\n /\\.key$/,\n /^.*_key$/, // aws_key, github_key, etc.\n];\n\n// Files that should trigger a warning\nconst SENSITIVE_FILE_PATTERNS = [\n /^\\.netrc$/,\n /^\\.aws\\/credentials$/,\n /^\\.docker\\/config\\.json$/,\n /^\\.npmrc$/, // May contain tokens\n /^\\.pypirc$/,\n /^\\.kube\\/config$/,\n /^\\.ssh\\/config$/,\n /^\\.gnupg\\//,\n /credentials/i,\n /secrets?/i,\n /tokens?\\.json$/i,\n /\\.env$/,\n /\\.env\\./,\n];\n\n/**\n * Check if a path is a private key (should never be tracked)\n */\nconst isPrivateKey = (path: string): boolean => {\n const name = basename(path);\n\n // SSH private keys (without .pub extension)\n if (path.includes('.ssh/') && !name.endsWith('.pub')) {\n for (const pattern of PRIVATE_KEY_PATTERNS) {\n if (pattern.test(name)) {\n return true;\n }\n }\n }\n\n // Other private key patterns\n if (name.endsWith('.pem') || name.endsWith('.key')) {\n return true;\n }\n\n return false;\n};\n\n/**\n * Check if a path contains potentially sensitive data\n */\nconst isSensitiveFile = (path: string): boolean => {\n // Strip ~/ prefix if present, since patterns with ^ anchor expect paths without it\n // e.g., ~/.netrc should match /^\\.netrc$/ pattern\n const pathToTest = path.startsWith('~/') ? path.slice(2) : path;\n\n for (const pattern of SENSITIVE_FILE_PATTERNS) {\n if (pattern.test(pathToTest)) {\n return true;\n }\n }\n return false;\n};\n\ninterface FileToAdd {\n source: string;\n destination: string;\n category: string;\n filename: string;\n isDir: boolean;\n fileCount: number;\n sensitive: boolean;\n}\n\nconst validateAndPrepareFiles = async (\n paths: string[],\n tuckDir: string,\n options: AddOptions\n): Promise<FileToAdd[]> => {\n const filesToAdd: FileToAdd[] = [];\n\n for (const path of paths) {\n const expandedPath = expandPath(path);\n const collapsedPath = collapsePath(expandedPath);\n\n // SECURITY: Block private keys\n if (isPrivateKey(collapsedPath)) {\n throw new Error(\n `Cannot track private key: ${path}\\n` +\n `Private keys should NEVER be committed to a repository.\\n` +\n `If you need to backup SSH keys, use a secure password manager.`\n );\n }\n\n // Check if file exists\n if (!(await pathExists(expandedPath))) {\n throw new FileNotFoundError(path);\n }\n\n // Check if already tracked\n if (await isFileTracked(tuckDir, collapsedPath)) {\n throw new FileAlreadyTrackedError(path);\n }\n\n // Check if in .tuckignore\n if (await isIgnored(tuckDir, collapsedPath)) {\n logger.info(`Skipping ${path} (in .tuckignore)`);\n continue;\n }\n\n // Check if binary executable in bin directory\n if (await shouldExcludeFromBin(expandedPath)) {\n const sizeCheck = await checkFileSizeThreshold(expandedPath);\n logger.info(\n `Skipping binary executable: ${path}${sizeCheck.size > 0 ? ` (${formatFileSize(sizeCheck.size)})` : ''}` +\n ` - Add to .tuckignore to customize`\n );\n continue;\n }\n\n // Check file size\n const sizeCheck = await checkFileSizeThreshold(expandedPath);\n\n if (sizeCheck.block) {\n // >= 100MB: Block and offer to ignore\n logger.warning(\n `File ${path} is ${formatFileSize(sizeCheck.size)} (exceeds GitHub's 100MB limit)`\n );\n\n const action = await prompts.select('How would you like to proceed?', [\n { value: 'ignore', label: 'Add to .tuckignore and skip' },\n { value: 'cancel', label: 'Cancel operation' },\n ]);\n\n if (action === 'ignore') {\n await addToTuckignore(tuckDir, collapsedPath);\n logger.success(`Added ${path} to .tuckignore`);\n continue; // Skip this file\n } else {\n throw new Error('Operation cancelled');\n }\n }\n\n if (sizeCheck.warn) {\n // 50-100MB: Warn and confirm\n logger.warning(\n `File ${path} is ${formatFileSize(sizeCheck.size)}. ` +\n `GitHub recommends files under 50MB.`\n );\n\n const action = await prompts.select('How would you like to proceed?', [\n { value: 'continue', label: 'Track it anyway' },\n { value: 'ignore', label: 'Add to .tuckignore and skip' },\n { value: 'cancel', label: 'Cancel operation' },\n ]);\n\n if (action === 'ignore') {\n await addToTuckignore(tuckDir, collapsedPath);\n logger.success(`Added ${path} to .tuckignore`);\n continue;\n } else if (action === 'cancel') {\n throw new Error('Operation cancelled');\n }\n // 'continue' falls through to track the file\n }\n\n // Determine if it's a directory\n const isDir = await isDirectory(expandedPath);\n const fileCount = isDir ? await getDirectoryFileCount(expandedPath) : 1;\n\n // Determine category\n const category = options.category || detectCategory(expandedPath);\n\n // Generate filename for storage\n const filename = options.name || sanitizeFilename(expandedPath);\n\n // Determine destination path\n const destination = getDestinationPath(tuckDir, category, filename);\n\n // Check if sensitive\n const sensitive = isSensitiveFile(collapsedPath);\n\n filesToAdd.push({\n source: collapsedPath,\n destination,\n category,\n filename,\n isDir,\n fileCount,\n sensitive,\n });\n }\n\n return filesToAdd;\n};\n\nconst addFiles = async (\n filesToAdd: FileToAdd[],\n tuckDir: string,\n options: AddOptions\n): Promise<void> => {\n // Convert FileToAdd to FileToTrack\n const filesToTrack: FileToTrack[] = filesToAdd.map((f) => ({\n path: f.source,\n category: f.category,\n }));\n\n // Use the shared tracking utility\n await trackFilesWithProgress(filesToTrack, tuckDir, {\n showCategory: true,\n strategy: options.symlink ? 'symlink' : undefined,\n actionVerb: 'Tracking',\n });\n};\n\n// ============================================================================\n// Secret Scanning Integration\n// ============================================================================\n\n/**\n * Display scan results in a formatted way\n */\nconst displaySecretWarning = (summary: ScanSummary): void => {\n console.log();\n console.log(\n c.error(c.bold(` Security Warning: Found ${summary.totalSecrets} potential secret(s)`))\n );\n console.log();\n\n for (const result of summary.results) {\n console.log(` ${c.brand(result.collapsedPath)}`);\n\n for (const match of result.matches) {\n const severityColor =\n match.severity === 'critical'\n ? c.error\n : match.severity === 'high'\n ? c.warning\n : match.severity === 'medium'\n ? c.info\n : c.muted;\n\n console.log(\n ` ${c.muted(`Line ${match.line}:`)} ${match.redactedValue} ${severityColor(`[${match.severity}]`)}`\n );\n }\n console.log();\n }\n};\n\n/**\n * Handle secret detection with interactive user prompt\n * Returns true if operation should continue, false if aborted\n */\nconst handleSecretsDetected = async (\n summary: ScanSummary,\n filesToAdd: FileToAdd[],\n tuckDir: string\n): Promise<{ continue: boolean; filesToAdd: FileToAdd[] }> => {\n displaySecretWarning(summary);\n\n const action = await prompts.select('How would you like to proceed?', [\n {\n value: 'abort',\n label: 'Abort operation',\n hint: 'Do not track these files',\n },\n {\n value: 'redact',\n label: 'Replace with placeholders',\n hint: 'Store originals in secrets.local.json (never committed)',\n },\n {\n value: 'ignore',\n label: 'Add files to .tuckignore',\n hint: 'Skip these files permanently',\n },\n {\n value: 'proceed',\n label: 'Proceed anyway',\n hint: 'Track files with secrets (dangerous!)',\n },\n ]);\n\n switch (action) {\n case 'abort':\n logger.info('Operation aborted');\n return { continue: false, filesToAdd: [] };\n\n case 'redact': {\n // Process secrets for redaction\n const redactionMaps = await processSecretsForRedaction(summary.results, tuckDir);\n\n // Redact each file\n let totalRedacted = 0;\n for (const result of summary.results) {\n const placeholderMap = redactionMaps.get(result.path);\n if (placeholderMap && placeholderMap.size > 0) {\n const redactionResult = await redactFile(result.path, result.matches, placeholderMap);\n totalRedacted += redactionResult.replacements.length;\n }\n }\n\n console.log();\n logger.success(`Replaced ${totalRedacted} secret(s) with placeholders`);\n logger.dim(`Secrets stored in: ${collapsePath(getSecretsPath(tuckDir))} (never committed)`);\n logger.dim(\"Run 'tuck secrets list' to see stored secrets\");\n console.log();\n\n return { continue: true, filesToAdd };\n }\n\n case 'ignore': {\n // Add files with secrets to .tuckignore\n const filesWithSecrets = new Set(summary.results.map((r) => r.collapsedPath));\n\n for (const file of filesToAdd) {\n // Normalize both paths for comparison using collapsePath\n const normalizedFileSource = collapsePath(file.source);\n if (filesWithSecrets.has(normalizedFileSource)) {\n await addToTuckignore(tuckDir, file.source);\n logger.success(`Added ${normalizedFileSource} to .tuckignore`);\n }\n }\n\n // Remove files with secrets from the list\n const remainingFiles = filesToAdd.filter((f) => {\n const normalizedSource = collapsePath(f.source);\n return !filesWithSecrets.has(normalizedSource);\n });\n\n if (remainingFiles.length === 0) {\n logger.info('No files remaining to track');\n return { continue: false, filesToAdd: [] };\n }\n\n return { continue: true, filesToAdd: remainingFiles };\n }\n\n case 'proceed': {\n // Double-confirm for dangerous action\n const confirmed = await prompts.confirm(\n c.error('Are you SURE you want to track files containing secrets?'),\n false\n );\n\n if (!confirmed) {\n logger.info('Operation aborted');\n return { continue: false, filesToAdd: [] };\n }\n\n logger.warning('Proceeding with secrets - be careful not to push to a public repository!');\n return { continue: true, filesToAdd };\n }\n\n default:\n return { continue: false, filesToAdd: [] };\n }\n};\n\n/**\n * Scan files for secrets and handle results\n * Returns updated filesToAdd list (may be modified by user choices)\n */\nconst scanAndHandleSecrets = async (\n filesToAdd: FileToAdd[],\n tuckDir: string,\n options: AddOptions\n): Promise<{ continue: boolean; filesToAdd: FileToAdd[] }> => {\n // Check if scanning is enabled\n const config = await loadConfig(tuckDir);\n const security = config.security || {};\n\n // Skip scanning if disabled or --force is used\n if (security.scanSecrets === false || options.force) {\n return { continue: true, filesToAdd };\n }\n\n // Get file paths for scanning\n const filePaths = filesToAdd.map((f) => expandPath(f.source));\n\n // Scan files\n const summary = await scanForSecrets(filePaths, tuckDir);\n\n // If no secrets found, continue normally\n if (summary.filesWithSecrets === 0) {\n return { continue: true, filesToAdd };\n }\n\n // Handle detected secrets\n return handleSecretsDetected(summary, filesToAdd, tuckDir);\n};\n\nconst runInteractiveAdd = async (tuckDir: string): Promise<void> => {\n prompts.intro('tuck add');\n\n // Ask for paths\n const pathsInput = await prompts.text('Enter file paths to track (space-separated):', {\n placeholder: '~/.zshrc ~/.gitconfig',\n validate: (value) => {\n if (!value.trim()) return 'At least one path is required';\n return undefined;\n },\n });\n\n const paths = pathsInput.split(/\\s+/).filter(Boolean);\n\n // Validate and prepare\n let filesToAdd: FileToAdd[];\n try {\n filesToAdd = await validateAndPrepareFiles(paths, tuckDir, {});\n } catch (error) {\n if (error instanceof Error) {\n prompts.log.error(error.message);\n }\n prompts.cancel();\n return;\n }\n\n // Show what will be added and ask for category confirmation\n for (const file of filesToAdd) {\n prompts.log.step(`${file.source}`);\n\n const categoryOptions = Object.entries(CATEGORIES).map(([name, config]) => ({\n value: name,\n label: `${config.icon} ${name}`,\n hint: file.category === name ? '(auto-detected)' : undefined,\n }));\n\n // Move detected category to top\n categoryOptions.sort((a, b) => {\n if (a.value === file.category) return -1;\n if (b.value === file.category) return 1;\n return 0;\n });\n\n const selectedCategory = await prompts.select('Category:', categoryOptions);\n file.category = selectedCategory as string;\n\n // Update destination with new category\n file.destination = getDestinationPath(tuckDir, file.category, file.filename);\n }\n\n // Confirm\n const confirm = await prompts.confirm(\n `Add ${filesToAdd.length} ${filesToAdd.length === 1 ? 'file' : 'files'}?`,\n true\n );\n\n if (!confirm) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n // Add files\n await addFiles(filesToAdd, tuckDir, {});\n\n prompts.outro(`Added ${filesToAdd.length} ${filesToAdd.length === 1 ? 'file' : 'files'}`);\n logger.info(\"Run 'tuck sync' to commit changes\");\n};\n\n/**\n * Add files programmatically (used by scan command)\n * Note: Throws SecretsDetectedError if secrets are found (unless --force is used)\n * Callers should catch this error and handle it appropriately\n */\nexport const addFilesFromPaths = async (\n paths: string[],\n options: AddOptions = {}\n): Promise<number> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Validate and prepare files\n const filesToAdd = await validateAndPrepareFiles(paths, tuckDir, options);\n\n if (filesToAdd.length === 0) {\n return 0;\n }\n\n // Scan for secrets (unless --force is used)\n if (!options.force) {\n const config = await loadConfig(tuckDir);\n const security = config.security || {};\n\n if (security.scanSecrets !== false) {\n const filePaths = filesToAdd.map((f) => expandPath(f.source));\n const summary = await scanForSecrets(filePaths, tuckDir);\n\n if (summary.filesWithSecrets > 0) {\n // Throw error to prevent silently adding files with secrets\n const filesWithSecrets = summary.results\n .filter((r) => r.hasSecrets)\n .map((r) => collapsePath(r.path));\n throw new SecretsDetectedError(summary.totalSecrets, filesWithSecrets);\n }\n }\n }\n\n // Add files\n await addFiles(filesToAdd, tuckDir, options);\n\n return filesToAdd.length;\n};\n\nconst runAdd = async (paths: string[], options: AddOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n if (paths.length === 0) {\n await runInteractiveAdd(tuckDir);\n return;\n }\n\n // Validate and prepare files\n let filesToAdd = await validateAndPrepareFiles(paths, tuckDir, options);\n\n if (filesToAdd.length === 0) {\n logger.info('No files to add');\n return;\n }\n\n // Scan for secrets (unless --force is used)\n const secretScanResult = await scanAndHandleSecrets(filesToAdd, tuckDir, options);\n if (!secretScanResult.continue) {\n return;\n }\n filesToAdd = secretScanResult.filesToAdd;\n\n if (filesToAdd.length === 0) {\n return;\n }\n\n // Add files\n await addFiles(filesToAdd, tuckDir, options);\n\n // Ask if user wants to sync now\n console.log();\n const shouldSync = await prompts.confirm('Would you like to sync these changes now?', true);\n\n if (shouldSync) {\n console.log();\n // Dynamically import sync to avoid circular dependencies\n const { runSync } = await import('./sync.js');\n await runSync({});\n } else {\n console.log();\n logger.info(\"Run 'tuck sync' when you're ready to commit changes\");\n }\n};\n\nexport const addCommand = new Command('add')\n .description('Track new dotfiles')\n .argument('[paths...]', 'Paths to dotfiles to track')\n .option('-c, --category <name>', 'Category to organize under')\n .option('-n, --name <name>', 'Custom name for the file in manifest')\n .option('--symlink', 'Create symlink instead of copy')\n .option('-f, --force', 'Skip secret scanning (not recommended)')\n // TODO: Encryption and templating are planned for a future version\n // .option('--encrypt', 'Encrypt this file (requires GPG setup)')\n // .option('--template', 'Treat as template with variable substitution')\n .action(async (paths: string[], options: AddOptions) => {\n await runAdd(paths, options);\n });\n","import { open, stat } from 'fs/promises';\nimport { expandPath } from './paths.js';\nimport { basename, dirname } from 'path';\n\n/**\n * Magic numbers for binary executable detection\n */\nconst MAGIC_NUMBERS = {\n // ELF (Linux)\n ELF: Buffer.from([0x7f, 0x45, 0x4c, 0x46]),\n // Mach-O (macOS) - 32-bit\n MACHO_32: Buffer.from([0xfe, 0xed, 0xfa, 0xce]),\n // Mach-O (macOS) - 64-bit\n MACHO_64: Buffer.from([0xcf, 0xfa, 0xed, 0xfe]),\n // Mach-O (macOS) - Universal binary\n MACHO_UNIVERSAL: Buffer.from([0xca, 0xfe, 0xba, 0xbe]),\n // PE (Windows)\n PE: Buffer.from([0x4d, 0x5a]), // \"MZ\"\n};\n\n/**\n * Script file extensions\n */\nconst SCRIPT_EXTENSIONS = [\n '.sh',\n '.bash',\n '.zsh',\n '.fish',\n '.py',\n '.rb',\n '.pl',\n '.js',\n '.ts',\n '.lua',\n '.php',\n '.tcl',\n '.awk',\n '.sed',\n];\n\n/**\n * Check if a buffer starts with a magic number\n */\nconst bufferStartsWith = (buffer: Buffer, magic: Buffer): boolean => {\n if (buffer.length < magic.length) {\n return false;\n }\n for (let i = 0; i < magic.length; i++) {\n if (buffer[i] !== magic[i]) {\n return false;\n }\n }\n return true;\n};\n\n/**\n * Check if file is an executable binary by reading magic numbers\n */\nexport const isBinaryExecutable = async (path: string): Promise<boolean> => {\n const expandedPath = expandPath(path);\n\n try {\n // Check if file exists and get stats\n const stats = await stat(expandedPath);\n\n // Directories are not binaries\n if (stats.isDirectory()) {\n return false;\n }\n\n // Check execute permissions (Unix-like systems)\n // 0o111 = execute bit for owner, group, and others\n const hasExecutePermission = (stats.mode & 0o111) !== 0;\n\n // Read first 512 bytes to check magic numbers\n let fileHandle;\n try {\n fileHandle = await open(expandedPath, 'r');\n const buffer = Buffer.alloc(512);\n await fileHandle.read(buffer, 0, 512, 0);\n\n // Check for binary magic numbers\n if (\n bufferStartsWith(buffer, MAGIC_NUMBERS.ELF) ||\n bufferStartsWith(buffer, MAGIC_NUMBERS.MACHO_32) ||\n bufferStartsWith(buffer, MAGIC_NUMBERS.MACHO_64) ||\n bufferStartsWith(buffer, MAGIC_NUMBERS.MACHO_UNIVERSAL) ||\n bufferStartsWith(buffer, MAGIC_NUMBERS.PE)\n ) {\n return true;\n }\n\n // If has execute permission but no magic number, might be a script\n // Check if it's actually a script (has shebang)\n if (hasExecutePermission) {\n const startsWithShebang = buffer[0] === 0x23 && buffer[1] === 0x21; // \"#!\"\n return !startsWithShebang; // Binary if no shebang\n }\n\n return false;\n } finally {\n if (fileHandle) {\n await fileHandle.close();\n }\n }\n } catch {\n // If any error occurs while checking the file (e.g. it does not exist,\n // cannot be accessed, or cannot be read), treat it as \"not an executable\n // binary\" and return false. Callers only rely on the boolean result.\n return false;\n }\n};\n\n/**\n * Check if file is a script based on shebang or extension\n */\nexport const isScriptFile = async (path: string): Promise<boolean> => {\n const expandedPath = expandPath(path);\n\n try {\n // Check extension first\n const hasScriptExtension = SCRIPT_EXTENSIONS.some((ext) => expandedPath.endsWith(ext));\n if (hasScriptExtension) {\n return true;\n }\n\n // Check for shebang\n const stats = await stat(expandedPath);\n if (stats.isDirectory()) {\n return false;\n }\n\n let fileHandle;\n try {\n fileHandle = await open(expandedPath, 'r');\n const buffer = Buffer.alloc(2);\n await fileHandle.read(buffer, 0, 2, 0);\n\n // Check for shebang \"#!\"\n return buffer[0] === 0x23 && buffer[1] === 0x21;\n } finally {\n if (fileHandle) {\n await fileHandle.close();\n }\n }\n } catch {\n // Any error while checking is treated as \"not a script\" to keep detection best-effort.\n // This includes file not found, permission denied, or read errors.\n return false;\n }\n};\n\n/**\n * Check if file should be excluded from bin directory tracking\n * Returns true for binary executables in ~/bin or ~/.local/bin\n * Returns false for script files\n */\nexport const shouldExcludeFromBin = async (path: string): Promise<boolean> => {\n const expandedPath = expandPath(path);\n\n // Check if file is in a bin directory by checking if parent directory is 'bin'\n // This matches both ~/bin and ~/.local/bin directories\n const parentDir = dirname(expandedPath);\n const parentBasename = basename(parentDir);\n \n const isInBinDir = parentBasename === 'bin';\n\n if (!isInBinDir) {\n return false;\n }\n\n // Check if it's a directory (don't exclude directories themselves)\n try {\n const stats = await stat(expandedPath);\n if (stats.isDirectory()) {\n return false;\n }\n } catch {\n return false;\n }\n\n // If it's a script, don't exclude it\n if (await isScriptFile(expandedPath)) {\n return false;\n }\n\n // If it's a binary executable, exclude it\n return await isBinaryExecutable(expandedPath);\n};\n\n/**\n * Get a human-readable description of why a file is being excluded\n */\nexport const getBinaryExclusionReason = async (path: string): Promise<string | null> => {\n if (await shouldExcludeFromBin(path)) {\n return 'Binary executable in bin directory';\n }\n return null;\n};\n\n","import { Command } from 'commander';\nimport { prompts, logger, withSpinner } from '../ui/index.js';\nimport {\n getTuckDir,\n expandPath,\n collapsePath,\n pathExists,\n} from '../lib/paths.js';\nimport { loadManifest, removeFileFromManifest, getTrackedFileBySource, getAllTrackedFiles } from '../lib/manifest.js';\nimport { deleteFileOrDir } from '../lib/files.js';\nimport { NotInitializedError, FileNotTrackedError } from '../errors.js';\nimport type { RemoveOptions } from '../types.js';\nimport { join } from 'path';\n\ninterface FileToRemove {\n id: string;\n source: string;\n destination: string;\n}\n\nconst validateAndPrepareFiles = async (\n paths: string[],\n tuckDir: string\n): Promise<FileToRemove[]> => {\n const filesToRemove: FileToRemove[] = [];\n\n for (const path of paths) {\n const expandedPath = expandPath(path);\n const collapsedPath = collapsePath(expandedPath);\n\n // Check if tracked\n const tracked = await getTrackedFileBySource(tuckDir, collapsedPath);\n if (!tracked) {\n throw new FileNotTrackedError(path);\n }\n\n filesToRemove.push({\n id: tracked.id,\n source: tracked.file.source,\n destination: join(tuckDir, tracked.file.destination),\n });\n }\n\n return filesToRemove;\n};\n\nconst removeFiles = async (\n filesToRemove: FileToRemove[],\n tuckDir: string,\n options: RemoveOptions\n): Promise<void> => {\n for (const file of filesToRemove) {\n // Remove from manifest\n await removeFileFromManifest(tuckDir, file.id);\n\n // Delete from repository if requested\n if (options.delete) {\n if (await pathExists(file.destination)) {\n await withSpinner(`Deleting ${file.source} from repository...`, async () => {\n await deleteFileOrDir(file.destination);\n });\n }\n }\n\n logger.success(`Removed ${file.source} from tracking`);\n if (options.delete) {\n logger.dim(' Also deleted from repository');\n }\n }\n};\n\nconst runInteractiveRemove = async (tuckDir: string): Promise<void> => {\n prompts.intro('tuck remove');\n\n // Get all tracked files\n const trackedFiles = await getAllTrackedFiles(tuckDir);\n const fileEntries = Object.entries(trackedFiles);\n\n if (fileEntries.length === 0) {\n prompts.log.warning('No files are currently tracked');\n prompts.outro('');\n return;\n }\n\n // Let user select files to remove\n const selectedFiles = await prompts.multiselect(\n 'Select files to stop tracking:',\n fileEntries.map(([id, file]) => ({\n value: id,\n label: file.source,\n hint: file.category,\n })),\n { required: true }\n );\n\n if (selectedFiles.length === 0) {\n prompts.cancel('No files selected');\n return;\n }\n\n // Ask if they want to delete from repo\n const shouldDelete = await prompts.confirm('Also delete files from repository?');\n\n // Confirm\n const confirm = await prompts.confirm(\n `Remove ${selectedFiles.length} ${selectedFiles.length === 1 ? 'file' : 'files'} from tracking?`,\n true\n );\n\n if (!confirm) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n // Prepare files to remove\n const filesToRemove: FileToRemove[] = selectedFiles.map((id) => {\n const file = trackedFiles[id as string];\n return {\n id: id as string,\n source: file.source,\n destination: join(tuckDir, file.destination),\n };\n });\n\n // Remove files\n await removeFiles(filesToRemove, tuckDir, { delete: shouldDelete });\n\n prompts.outro(`Removed ${selectedFiles.length} ${selectedFiles.length === 1 ? 'file' : 'files'}`);\n logger.info(\"Run 'tuck sync' to commit changes\");\n};\n\nconst runRemove = async (paths: string[], options: RemoveOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n if (paths.length === 0) {\n await runInteractiveRemove(tuckDir);\n return;\n }\n\n // Validate and prepare files\n const filesToRemove = await validateAndPrepareFiles(paths, tuckDir);\n\n // Remove files\n await removeFiles(filesToRemove, tuckDir, options);\n\n logger.blank();\n logger.success(`Removed ${filesToRemove.length} ${filesToRemove.length === 1 ? 'item' : 'items'} from tracking`);\n logger.info(\"Run 'tuck sync' to commit changes\");\n};\n\nexport const removeCommand = new Command('remove')\n .description('Stop tracking dotfiles')\n .argument('[paths...]', 'Paths to dotfiles to untrack')\n .option('--delete', 'Also delete from tuck repository')\n .option('--keep-original', \"Don't restore symlinks to regular files\")\n .action(async (paths: string[], options: RemoveOptions) => {\n await runRemove(paths, options);\n });\n","export { initCommand } from './init.js';\nexport { addCommand } from './add.js';\nexport { removeCommand } from './remove.js';\nexport { syncCommand } from './sync.js';\nexport { pushCommand } from './push.js';\nexport { pullCommand } from './pull.js';\nexport { restoreCommand } from './restore.js';\nexport { statusCommand } from './status.js';\nexport { listCommand } from './list.js';\nexport { diffCommand } from './diff.js';\nexport { configCommand } from './config.js';\nexport { applyCommand } from './apply.js';\nexport { undoCommand } from './undo.js';\nexport { scanCommand } from './scan.js';\nexport { secretsCommand } from './secrets.js';\n","import { Command } from 'commander';\nimport { prompts, logger, withSpinner, colors as c } from '../ui/index.js';\nimport { getTuckDir } from '../lib/paths.js';\nimport { loadManifest } from '../lib/manifest.js';\nimport {\n push,\n hasRemote,\n getRemoteUrl,\n getStatus,\n getCurrentBranch,\n addRemote,\n} from '../lib/git.js';\nimport { NotInitializedError, GitError } from '../errors.js';\nimport type { PushOptions } from '../types.js';\n\nconst runInteractivePush = async (tuckDir: string): Promise<void> => {\n prompts.intro('tuck push');\n\n // Check if remote exists\n const hasRemoteRepo = await hasRemote(tuckDir);\n\n if (!hasRemoteRepo) {\n prompts.log.warning('No remote configured');\n\n const addRemoteNow = await prompts.confirm('Would you like to add a remote?');\n if (!addRemoteNow) {\n prompts.cancel('No remote to push to');\n return;\n }\n\n const remoteUrl = await prompts.text('Enter remote URL:', {\n placeholder: 'git@github.com:user/dotfiles.git',\n validate: (value) => {\n if (!value) return 'Remote URL is required';\n return undefined;\n },\n });\n\n await addRemote(tuckDir, 'origin', remoteUrl);\n prompts.log.success('Remote added');\n }\n\n // Get current status\n const status = await getStatus(tuckDir);\n const branch = await getCurrentBranch(tuckDir);\n const remoteUrl = await getRemoteUrl(tuckDir);\n\n if (status.ahead === 0 && status.tracking) {\n prompts.log.success('Already up to date with remote');\n return;\n }\n\n // Show what will be pushed\n console.log();\n console.log(c.dim('Remote:'), remoteUrl);\n console.log(c.dim('Branch:'), branch);\n\n if (status.ahead > 0) {\n console.log(c.dim('Commits:'), c.green(`↑ ${status.ahead} to push`));\n }\n\n if (status.behind > 0) {\n console.log(c.dim('Warning:'), c.yellow(`↓ ${status.behind} commits behind remote`));\n\n const pullFirst = await prompts.confirm('Pull changes first?', true);\n if (pullFirst) {\n prompts.log.info(\"Run 'tuck pull' first, then push\");\n return;\n }\n }\n\n console.log();\n\n // Confirm\n const confirm = await prompts.confirm('Push to remote?', true);\n if (!confirm) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n // Push\n const needsUpstream = !status.tracking;\n\n try {\n await withSpinner('Pushing...', async () => {\n await push(tuckDir, {\n setUpstream: needsUpstream,\n branch: needsUpstream ? branch : undefined,\n });\n });\n prompts.log.success('Pushed successfully!');\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n\n // Provide specific guidance based on common errors\n if (errorMsg.includes('Permission denied') || errorMsg.includes('publickey')) {\n prompts.log.error('Authentication failed');\n prompts.log.info('Check your SSH keys with: ssh -T git@github.com');\n prompts.log.info('Or try switching to HTTPS: git remote set-url origin https://...');\n } else if (errorMsg.includes('Could not resolve host') || errorMsg.includes('Network')) {\n prompts.log.error('Network error - could not reach remote');\n prompts.log.info('Check your internet connection and try again');\n } else if (errorMsg.includes('rejected') || errorMsg.includes('non-fast-forward')) {\n prompts.log.error('Push rejected - remote has changes');\n prompts.log.info(\"Run 'tuck pull' first, then push again\");\n prompts.log.info(\"Or use 'tuck push --force' to overwrite (use with caution)\");\n } else {\n prompts.log.error(`Push failed: ${errorMsg}`);\n }\n return;\n }\n\n if (remoteUrl) {\n // Extract repo URL for display\n let viewUrl = remoteUrl;\n if (remoteUrl.startsWith('git@github.com:')) {\n viewUrl = remoteUrl.replace('git@github.com:', 'https://github.com/').replace('.git', '');\n }\n console.log();\n console.log(c.dim('View at:'), c.cyan(viewUrl));\n }\n\n prompts.outro('');\n};\n\nconst runPush = async (options: PushOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // If no options, run interactive\n if (!options.force && !options.setUpstream) {\n await runInteractivePush(tuckDir);\n return;\n }\n\n // Check if remote exists\n const hasRemoteRepo = await hasRemote(tuckDir);\n if (!hasRemoteRepo) {\n throw new GitError('No remote configured', \"Run 'tuck init -r <url>' or add a remote manually\");\n }\n\n const branch = await getCurrentBranch(tuckDir);\n\n try {\n await withSpinner('Pushing...', async () => {\n await push(tuckDir, {\n force: options.force,\n setUpstream: Boolean(options.setUpstream),\n branch: options.setUpstream || branch,\n });\n });\n logger.success('Pushed successfully!');\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n\n if (errorMsg.includes('Permission denied') || errorMsg.includes('publickey')) {\n throw new GitError('Authentication failed', 'Check your SSH keys: ssh -T git@github.com');\n } else if (errorMsg.includes('Could not resolve host') || errorMsg.includes('Network')) {\n throw new GitError('Network error', 'Check your internet connection');\n } else if (errorMsg.includes('rejected') || errorMsg.includes('non-fast-forward')) {\n throw new GitError('Push rejected', \"Run 'tuck pull' first, or use --force\");\n } else {\n throw new GitError('Push failed', errorMsg);\n }\n }\n};\n\nexport const pushCommand = new Command('push')\n .description('Push changes to remote repository')\n .option('-f, --force', 'Force push')\n .option('--set-upstream <name>', 'Set upstream branch')\n .action(async (options: PushOptions) => {\n await runPush(options);\n });\n","import { Command } from 'commander';\nimport { prompts, logger, withSpinner, colors as c } from '../ui/index.js';\nimport { getTuckDir } from '../lib/paths.js';\nimport { loadManifest } from '../lib/manifest.js';\nimport { pull, fetch, hasRemote, getRemoteUrl, getStatus, getCurrentBranch } from '../lib/git.js';\nimport { NotInitializedError, GitError } from '../errors.js';\nimport type { PullOptions } from '../types.js';\n\nconst runInteractivePull = async (tuckDir: string): Promise<void> => {\n prompts.intro('tuck pull');\n\n // Check if remote exists\n const hasRemoteRepo = await hasRemote(tuckDir);\n if (!hasRemoteRepo) {\n prompts.log.error('No remote configured');\n prompts.note(\"Run 'tuck init -r <url>' or add a remote manually\", 'Tip');\n return;\n }\n\n // Fetch first to get latest remote status\n await withSpinner('Fetching...', async () => {\n await fetch(tuckDir);\n });\n\n // Get current status\n const status = await getStatus(tuckDir);\n const branch = await getCurrentBranch(tuckDir);\n const remoteUrl = await getRemoteUrl(tuckDir);\n\n // Show status\n console.log();\n console.log(c.dim('Remote:'), remoteUrl);\n console.log(c.dim('Branch:'), branch);\n\n if (status.behind === 0) {\n prompts.log.success('Already up to date');\n return;\n }\n\n console.log(c.dim('Commits:'), c.yellow(`↓ ${status.behind} to pull`));\n\n if (status.ahead > 0) {\n console.log(\n c.dim('Note:'),\n c.yellow(`You also have ${status.ahead} local commit${status.ahead > 1 ? 's' : ''} to push`)\n );\n }\n\n // Check for local changes\n if (status.modified.length > 0 || status.staged.length > 0) {\n console.log();\n prompts.log.warning('You have uncommitted changes');\n console.log(c.dim('Modified:'), status.modified.join(', '));\n\n const continueAnyway = await prompts.confirm('Pull anyway? (may cause merge conflicts)');\n if (!continueAnyway) {\n prompts.cancel(\"Commit or stash your changes first with 'tuck sync'\");\n return;\n }\n }\n\n console.log();\n\n // Ask about rebase\n const useRebase = await prompts.confirm('Use rebase instead of merge?');\n\n // Pull\n await withSpinner('Pulling...', async () => {\n await pull(tuckDir, { rebase: useRebase });\n });\n\n prompts.log.success('Pulled successfully!');\n\n // Ask about restore\n const shouldRestore = await prompts.confirm('Restore updated dotfiles to system?', true);\n if (shouldRestore) {\n prompts.note(\"Run 'tuck restore --all' to restore all dotfiles\", 'Next step');\n }\n\n prompts.outro('');\n};\n\nconst runPull = async (options: PullOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // If no options, run interactive\n if (!options.rebase && !options.restore) {\n await runInteractivePull(tuckDir);\n return;\n }\n\n // Check if remote exists\n const hasRemoteRepo = await hasRemote(tuckDir);\n if (!hasRemoteRepo) {\n throw new GitError('No remote configured', \"Run 'tuck init -r <url>' or add a remote manually\");\n }\n\n // Fetch first\n await withSpinner('Fetching...', async () => {\n await fetch(tuckDir);\n });\n\n // Pull\n await withSpinner('Pulling...', async () => {\n await pull(tuckDir, { rebase: options.rebase });\n });\n\n logger.success('Pulled successfully!');\n\n if (options.restore) {\n logger.info(\"Run 'tuck restore --all' to restore dotfiles\");\n }\n};\n\nexport const pullCommand = new Command('pull')\n .description('Pull changes from remote')\n .option('--rebase', 'Pull with rebase')\n .option('--restore', 'Also restore files to system after pull')\n .action(async (options: PullOptions) => {\n await runPull(options);\n });\n","/**\n * Status command for tuck CLI\n * Shows current tracking status in a compact, modern layout\n */\n\nimport { Command } from 'commander';\nimport boxen from 'boxen';\nimport logSymbols from 'log-symbols';\nimport figures from 'figures';\nimport { colors as c, boxStyles, indent, formatStatus, categoryStyles } from '../ui/index.js';\nimport { prompts } from '../ui/prompts.js';\nimport { getTuckDir, collapsePath, expandPath, pathExists } from '../lib/paths.js';\nimport { loadManifest, getAllTrackedFiles } from '../lib/manifest.js';\nimport { getStatus, hasRemote, getRemoteUrl, getCurrentBranch } from '../lib/git.js';\nimport { getFileChecksum } from '../lib/files.js';\nimport { loadTuckignore } from '../lib/tuckignore.js';\nimport { NotInitializedError } from '../errors.js';\nimport { VERSION } from '../constants.js';\nimport type { StatusOptions, FileChange } from '../types.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface TuckStatus {\n tuckDir: string;\n branch: string;\n remote?: string;\n remoteStatus: 'up-to-date' | 'ahead' | 'behind' | 'diverged' | 'no-remote';\n ahead: number;\n behind: number;\n trackedCount: number;\n categoryCounts: Record<string, number>;\n changes: FileChange[];\n gitChanges: {\n staged: string[];\n modified: string[];\n untracked: string[];\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Status Detection\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst detectFileChanges = async (tuckDir: string): Promise<FileChange[]> => {\n const files = await getAllTrackedFiles(tuckDir);\n const ignoredPaths = await loadTuckignore(tuckDir);\n const changes: FileChange[] = [];\n\n for (const [, file] of Object.entries(files)) {\n if (ignoredPaths.has(file.source)) {\n continue;\n }\n\n const sourcePath = expandPath(file.source);\n\n if (!(await pathExists(sourcePath))) {\n changes.push({\n path: file.source,\n status: 'deleted',\n source: file.source,\n destination: file.destination,\n });\n continue;\n }\n\n try {\n const sourceChecksum = await getFileChecksum(sourcePath);\n if (sourceChecksum !== file.checksum) {\n changes.push({\n path: file.source,\n status: 'modified',\n source: file.source,\n destination: file.destination,\n });\n }\n } catch {\n changes.push({\n path: file.source,\n status: 'modified',\n source: file.source,\n destination: file.destination,\n });\n }\n }\n\n return changes;\n};\n\nconst getFullStatus = async (tuckDir: string): Promise<TuckStatus> => {\n const manifest = await loadManifest(tuckDir);\n const gitStatus = await getStatus(tuckDir);\n const branch = await getCurrentBranch(tuckDir);\n const hasRemoteRepo = await hasRemote(tuckDir);\n const remoteUrl = hasRemoteRepo ? await getRemoteUrl(tuckDir) : undefined;\n\n let remoteStatus: TuckStatus['remoteStatus'] = 'no-remote';\n if (hasRemoteRepo) {\n if (gitStatus.ahead > 0 && gitStatus.behind > 0) {\n remoteStatus = 'diverged';\n } else if (gitStatus.ahead > 0) {\n remoteStatus = 'ahead';\n } else if (gitStatus.behind > 0) {\n remoteStatus = 'behind';\n } else {\n remoteStatus = 'up-to-date';\n }\n }\n\n const fileChanges = await detectFileChanges(tuckDir);\n\n const categoryCounts: Record<string, number> = {};\n for (const file of Object.values(manifest.files)) {\n categoryCounts[file.category] = (categoryCounts[file.category] || 0) + 1;\n }\n\n return {\n tuckDir,\n branch,\n remote: remoteUrl || undefined,\n remoteStatus,\n ahead: gitStatus.ahead,\n behind: gitStatus.behind,\n trackedCount: Object.keys(manifest.files).length,\n categoryCounts,\n changes: fileChanges,\n gitChanges: {\n staged: gitStatus.staged,\n modified: gitStatus.modified,\n untracked: gitStatus.untracked,\n },\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output Formatting\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst formatRemoteUrl = (url: string): string => {\n // Shorten common patterns\n return url\n .replace(/^https?:\\/\\//, '')\n .replace(/\\.git$/, '')\n .replace(/^github\\.com\\//, '');\n};\n\nconst printStatus = (status: TuckStatus): void => {\n // Header box\n const headerLines: string[] = [\n `${c.brandBold('tuck')} ${c.muted(`v${VERSION}`)}`,\n '',\n `${c.muted('Repository:')} ${collapsePath(status.tuckDir)}`,\n `${c.muted('Branch:')} ${c.brand(status.branch)}`,\n ];\n\n if (status.remote) {\n headerLines.push(`${c.muted('Remote:')} ${formatRemoteUrl(status.remote)}`);\n } else {\n headerLines.push(`${c.muted('Remote:')} ${c.warning('not configured')}`);\n }\n\n console.log(boxen(headerLines.join('\\n'), boxStyles.header));\n\n // Remote status\n if (status.remote) {\n console.log();\n switch (status.remoteStatus) {\n case 'up-to-date':\n console.log(logSymbols.success, c.success('Up to date with remote'));\n break;\n case 'ahead':\n console.log(\n c.warning(figures.arrowUp),\n c.warning(`${status.ahead} commit${status.ahead > 1 ? 's' : ''} ahead`)\n );\n break;\n case 'behind':\n console.log(\n c.warning(figures.arrowDown),\n c.warning(`${status.behind} commit${status.behind > 1 ? 's' : ''} behind`)\n );\n break;\n case 'diverged':\n console.log(\n logSymbols.warning,\n c.error(`Diverged (${status.ahead} ahead, ${status.behind} behind)`)\n );\n break;\n }\n }\n\n // Tracked files summary\n console.log();\n console.log(c.bold(`${status.trackedCount} files tracked`));\n\n // Category breakdown (inline, compact)\n const categoryOrder = ['shell', 'git', 'editors', 'terminal', 'ssh', 'misc'];\n const sortedCategories = Object.keys(status.categoryCounts).sort((a, b) => {\n const aIdx = categoryOrder.indexOf(a);\n const bIdx = categoryOrder.indexOf(b);\n if (aIdx === -1 && bIdx === -1) return a.localeCompare(b);\n if (aIdx === -1) return 1;\n if (bIdx === -1) return -1;\n return aIdx - bIdx;\n });\n\n if (sortedCategories.length > 0) {\n const categoryLine = sortedCategories\n .map((cat) => {\n const style = categoryStyles[cat] || categoryStyles.misc;\n const count = status.categoryCounts[cat];\n return `${style.color(style.icon)} ${cat}: ${count}`;\n })\n .join(' ');\n console.log(c.muted(indent() + categoryLine));\n }\n\n // File changes\n if (status.changes.length > 0) {\n console.log();\n console.log(c.bold('Changes:'));\n for (const change of status.changes) {\n const statusText = formatStatus(change.status);\n console.log(`${indent()}${statusText} ${c.brand(change.path)}`);\n }\n }\n\n // Git changes\n const hasGitChanges =\n status.gitChanges.staged.length > 0 ||\n status.gitChanges.modified.length > 0 ||\n status.gitChanges.untracked.length > 0;\n\n if (hasGitChanges) {\n console.log();\n console.log(c.bold('Repository:'));\n\n if (status.gitChanges.staged.length > 0) {\n console.log(c.success(`${indent()}Staged:`));\n status.gitChanges.staged.forEach((f) =>\n console.log(c.success(`${indent()}${indent()}+ ${f}`))\n );\n }\n\n if (status.gitChanges.modified.length > 0) {\n console.log(c.warning(`${indent()}Modified:`));\n status.gitChanges.modified.forEach((f) =>\n console.log(c.warning(`${indent()}${indent()}~ ${f}`))\n );\n }\n\n if (status.gitChanges.untracked.length > 0) {\n console.log(c.muted(`${indent()}Untracked:`));\n status.gitChanges.untracked.forEach((f) =>\n console.log(c.muted(`${indent()}${indent()}? ${f}`))\n );\n }\n }\n\n console.log();\n\n // Next step suggestion\n if (status.changes.length > 0) {\n prompts.note(\"Run 'tuck sync' to commit changes\", 'Next');\n } else if (status.remoteStatus === 'ahead') {\n prompts.note(\"Run 'tuck push' to push changes\", 'Next');\n } else if (status.remoteStatus === 'behind') {\n prompts.note(\"Run 'tuck pull' to pull changes\", 'Next');\n } else if (status.trackedCount === 0) {\n prompts.note(\"Run 'tuck add <path>' to start tracking\", 'Next');\n } else {\n prompts.outro('Everything up to date');\n }\n};\n\nconst printShortStatus = (status: TuckStatus): void => {\n const parts: string[] = [];\n\n parts.push(`[${status.branch}]`);\n\n if (status.remoteStatus === 'ahead') {\n parts.push(c.warning(`${figures.arrowUp}${status.ahead}`));\n } else if (status.remoteStatus === 'behind') {\n parts.push(c.warning(`${figures.arrowDown}${status.behind}`));\n } else if (status.remoteStatus === 'diverged') {\n parts.push(c.error(`${figures.arrowUp}${status.ahead}${figures.arrowDown}${status.behind}`));\n }\n\n if (status.changes.length > 0) {\n const modified = status.changes.filter((ch) => ch.status === 'modified').length;\n const deleted = status.changes.filter((ch) => ch.status === 'deleted').length;\n if (modified > 0) parts.push(c.warning(`~${modified}`));\n if (deleted > 0) parts.push(c.error(`-${deleted}`));\n }\n\n parts.push(c.muted(`(${status.trackedCount} tracked)`));\n\n console.log(parts.join(' '));\n};\n\nconst printJsonStatus = (status: TuckStatus): void => {\n console.log(JSON.stringify(status, null, 2));\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Command Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst runStatus = async (options: StatusOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n const status = await getFullStatus(tuckDir);\n\n if (options.json) {\n printJsonStatus(status);\n } else if (options.short) {\n printShortStatus(status);\n } else {\n printStatus(status);\n }\n};\n\nexport const statusCommand = new Command('status')\n .description('Show current tracking status')\n .option('--short', 'Short format')\n .option('--json', 'Output as JSON')\n .action(async (options: StatusOptions) => {\n await runStatus(options);\n });\n","import { Command } from 'commander';\nimport { prompts, logger, formatCount, colors as c } from '../ui/index.js';\nimport { getTuckDir } from '../lib/paths.js';\nimport { loadManifest, getAllTrackedFiles } from '../lib/manifest.js';\nimport { NotInitializedError } from '../errors.js';\nimport { CATEGORIES } from '../constants.js';\nimport type { ListOptions } from '../types.js';\n\ninterface CategoryGroup {\n name: string;\n icon: string;\n files: { id: string; source: string; destination: string; isDir: boolean }[];\n}\n\nconst groupByCategory = async (tuckDir: string): Promise<CategoryGroup[]> => {\n const files = await getAllTrackedFiles(tuckDir);\n const groups: Map<string, CategoryGroup> = new Map();\n\n for (const [id, file] of Object.entries(files)) {\n const category = file.category;\n const categoryConfig = CATEGORIES[category] || { icon: '📄' };\n\n if (!groups.has(category)) {\n groups.set(category, {\n name: category,\n icon: categoryConfig.icon,\n files: [],\n });\n }\n\n groups.get(category)!.files.push({\n id,\n source: file.source,\n destination: file.destination,\n isDir: file.destination.endsWith('/') || file.destination.includes('nvim'),\n });\n }\n\n // Sort groups by name and files within each group\n return Array.from(groups.values())\n .sort((a, b) => a.name.localeCompare(b.name))\n .map((group) => ({\n ...group,\n files: group.files.sort((a, b) => a.source.localeCompare(b.source)),\n }));\n};\n\nconst printList = (groups: CategoryGroup[]): void => {\n prompts.intro('tuck list');\n\n if (groups.length === 0) {\n prompts.log.warning('No files are currently tracked');\n prompts.note(\"Run 'tuck add <path>' to start tracking files\", 'Tip');\n return;\n }\n\n let totalFiles = 0;\n\n for (const group of groups) {\n const fileCount = group.files.length;\n totalFiles += fileCount;\n\n console.log();\n console.log(\n c.bold(`${group.icon} ${group.name}`) + c.dim(` (${formatCount(fileCount, 'file')})`)\n );\n\n group.files.forEach((file, index) => {\n const isLast = index === group.files.length - 1;\n const prefix = isLast ? '└── ' : '├── ';\n const name = file.source.split('/').pop() || file.source;\n const arrow = c.dim(' → ');\n const dest = c.dim(file.source);\n\n console.log(c.dim(prefix) + c.cyan(name) + arrow + dest);\n });\n }\n\n console.log();\n prompts.outro(`Total: ${formatCount(totalFiles, 'tracked item')}`);\n};\n\nconst printPathsOnly = (groups: CategoryGroup[]): void => {\n for (const group of groups) {\n for (const file of group.files) {\n console.log(file.source);\n }\n }\n};\n\nconst printJson = (groups: CategoryGroup[]): void => {\n const output = groups.reduce(\n (acc, group) => {\n acc[group.name] = group.files.map((f) => ({\n source: f.source,\n destination: f.destination,\n }));\n return acc;\n },\n {} as Record<string, { source: string; destination: string }[]>\n );\n\n console.log(JSON.stringify(output, null, 2));\n};\n\nconst runList = async (options: ListOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n let groups = await groupByCategory(tuckDir);\n\n // Filter by category if specified\n if (options.category) {\n groups = groups.filter((g) => g.name === options.category);\n if (groups.length === 0) {\n logger.warning(`No files found in category: ${options.category}`);\n return;\n }\n }\n\n // Output based on format\n if (options.json) {\n printJson(groups);\n } else if (options.paths) {\n printPathsOnly(groups);\n } else {\n printList(groups);\n }\n};\n\nexport const listCommand = new Command('list')\n .description('List all tracked files')\n .option('-c, --category <name>', 'Filter by category')\n .option('--paths', 'Show only paths')\n .option('--json', 'Output as JSON')\n .action(async (options: ListOptions) => {\n await runList(options);\n });\n","import { Command } from 'commander';\nimport { join } from 'path';\nimport { prompts, logger } from '../ui/index.js';\nimport { colors as c } from '../ui/theme.js';\nimport { getTuckDir, expandPath, pathExists, collapsePath, isDirectory } from '../lib/paths.js';\nimport { loadManifest, getAllTrackedFiles, getTrackedFileBySource } from '../lib/manifest.js';\nimport { getDiff } from '../lib/git.js';\nimport {\n getFileChecksum,\n checkFileSizeThreshold,\n formatFileSize,\n getDirectoryFiles,\n} from '../lib/files.js';\nimport { NotInitializedError, FileNotFoundError, PermissionError } from '../errors.js';\nimport { isBinaryExecutable } from '../lib/binary.js';\nimport { isIgnored } from '../lib/tuckignore.js';\nimport type { DiffOptions } from '../types.js';\nimport { readFile } from 'fs/promises';\n\ninterface FileDiff {\n source: string;\n destination: string;\n hasChanges: boolean;\n isBinary?: boolean;\n isDirectory?: boolean;\n fileCount?: number;\n systemSize?: number;\n repoSize?: number;\n systemContent?: string;\n repoContent?: string;\n}\n\nconst isBinary = async (path: string): Promise<boolean> => {\n if (!(await pathExists(path))) {\n return false;\n }\n return await isBinaryExecutable(path);\n};\n\nconst getFileDiff = async (tuckDir: string, source: string): Promise<FileDiff | null> => {\n const tracked = await getTrackedFileBySource(tuckDir, source);\n if (!tracked) {\n throw new FileNotFoundError(`Not tracked: ${source}`);\n }\n\n const systemPath = expandPath(source);\n const repoPath = join(tuckDir, tracked.file.destination);\n\n const diff: FileDiff = {\n source,\n destination: tracked.file.destination,\n hasChanges: false,\n };\n\n const systemExists = await pathExists(systemPath);\n const repoExists = await pathExists(repoPath);\n\n // Check if system file exists\n if (!systemExists) {\n diff.hasChanges = true;\n if (repoExists) {\n // Check if repo file is a directory\n if (await isDirectory(repoPath)) {\n diff.isDirectory = true;\n const files = await getDirectoryFiles(repoPath);\n diff.fileCount = files.length;\n } else {\n const repoContent = await readFile(repoPath, 'utf-8');\n diff.repoContent = repoContent;\n diff.repoSize = repoContent.length;\n }\n }\n return diff;\n }\n\n // Check if repo file exists\n if (!repoExists) {\n diff.hasChanges = true;\n // Check if system file is a directory\n if (await isDirectory(systemPath)) {\n diff.isDirectory = true;\n const files = await getDirectoryFiles(systemPath);\n diff.fileCount = files.length;\n } else {\n const systemContent = await readFile(systemPath, 'utf-8');\n diff.systemContent = systemContent;\n diff.systemSize = systemContent.length;\n }\n return diff;\n }\n\n // Check if directory (both exist now)\n const systemIsDir = await isDirectory(systemPath);\n const repoIsDir = await isDirectory(repoPath);\n\n if (systemIsDir || repoIsDir) {\n diff.isDirectory = true;\n\n // Get file counts for directory summary\n if (systemIsDir) {\n const files = await getDirectoryFiles(systemPath);\n diff.fileCount = files.length;\n }\n if (repoIsDir) {\n const files = await getDirectoryFiles(repoPath);\n diff.fileCount = (diff.fileCount || 0) + files.length;\n }\n\n // Compare checksums for directories too\n const systemChecksum = await getFileChecksum(systemPath);\n const repoChecksum = await getFileChecksum(repoPath);\n diff.hasChanges = systemChecksum !== repoChecksum;\n\n return diff;\n }\n\n // Check if binary\n const systemIsBinary = await isBinary(systemPath);\n const repoIsBinary = await isBinary(repoPath);\n\n if (systemIsBinary || repoIsBinary) {\n diff.isBinary = true;\n\n // Compare binary files using checksums\n const systemChecksum = await getFileChecksum(systemPath);\n const repoChecksum = await getFileChecksum(repoPath);\n diff.hasChanges = systemChecksum !== repoChecksum;\n\n try {\n const systemBuffer = await readFile(systemPath);\n diff.systemSize = systemBuffer.length;\n } catch {\n // Ignore read errors for binaries\n }\n try {\n const repoBuffer = await readFile(repoPath);\n diff.repoSize = repoBuffer.length;\n } catch {\n // Ignore read errors for binaries\n }\n return diff;\n }\n\n // Check file size for large files\n try {\n const systemSizeCheck = await checkFileSizeThreshold(systemPath);\n const repoSizeCheck = await checkFileSizeThreshold(repoPath);\n\n diff.systemSize = systemSizeCheck.size;\n diff.repoSize = repoSizeCheck.size;\n } catch {\n // Size check failed, continue with diff\n }\n\n // Compare checksums for text files\n const systemChecksum = await getFileChecksum(systemPath);\n const repoChecksum = await getFileChecksum(repoPath);\n\n if (systemChecksum !== repoChecksum) {\n diff.hasChanges = true;\n diff.systemContent = await readFile(systemPath, 'utf-8');\n diff.repoContent = await readFile(repoPath, 'utf-8');\n }\n\n return diff;\n};\n\nconst formatUnifiedDiff = (diff: FileDiff): string => {\n const lines: string[] = [];\n\n lines.push(c.bold(`--- a/${diff.source} (system)`));\n lines.push(c.bold(`+++ b/${diff.source} (repository)`));\n\n if (diff.isBinary) {\n const sysSize = diff.systemSize ? formatFileSize(diff.systemSize) : '0 B';\n const repoSize = diff.repoSize ? formatFileSize(diff.repoSize) : '0 B';\n lines.push(c.dim('Binary files differ'));\n lines.push(c.dim(` System: ${sysSize}`));\n lines.push(c.dim(` Repo: ${repoSize}`));\n return lines.join('\\n');\n }\n\n if (diff.isDirectory) {\n const fileCount = diff.fileCount || 0;\n lines.push(c.dim('Directory content changed'));\n lines.push(c.dim(` Contains ${fileCount} file${fileCount > 1 ? 's' : ''}`));\n return lines.join('\\n');\n }\n\n const { systemContent, repoContent } = diff;\n\n // Check if systemContent is explicitly undefined (missing) vs empty string\n const systemMissing = systemContent === undefined;\n const repoMissing = repoContent === undefined;\n\n if (systemMissing && !repoMissing) {\n // File only in repo\n lines.push(c.red('File missing on system'));\n lines.push(c.dim('Repository content:'));\n repoContent!.split('\\n').forEach((line) => {\n lines.push(c.green(`+ ${line}`));\n });\n } else if (!systemMissing && repoMissing) {\n // File only on system\n lines.push(c.yellow('File not yet synced to repository'));\n lines.push(c.dim('System content:'));\n systemContent!.split('\\n').forEach((line) => {\n lines.push(c.red(`- ${line}`));\n });\n } else if (!systemMissing && !repoMissing) {\n // Both files exist (may be empty)\n const CONTEXT_LINES = 3;\n const systemLines = systemContent!.split('\\n');\n const repoLines = repoContent!.split('\\n');\n\n const maxLines = Math.max(systemLines.length, repoLines.length);\n\n let inDiff = false;\n let diffStart = 0;\n\n for (let i = 0; i < maxLines; i++) {\n const sysLine = systemLines[i];\n const repoLine = repoLines[i];\n\n if (sysLine !== repoLine) {\n if (!inDiff) {\n inDiff = true;\n diffStart = i;\n const startLine = Math.max(0, diffStart - CONTEXT_LINES + 1);\n const contextLineCount = Math.min(diffStart, CONTEXT_LINES);\n const endLine = Math.min(maxLines, diffStart + CONTEXT_LINES + 1);\n\n lines.push(\n c.cyan(\n `@@ -${startLine + 1},${contextLineCount + 1} +${startLine + 1},${endLine - startLine} @@`\n )\n );\n\n // Print context lines before diff\n for (let j = startLine; j < i; j++) {\n const ctxLine = systemLines[j];\n if (ctxLine !== undefined) {\n lines.push(c.dim(` ${ctxLine}`));\n }\n }\n }\n\n if (sysLine !== undefined) {\n lines.push(c.red(`- ${sysLine}`));\n }\n if (repoLine !== undefined) {\n lines.push(c.green(`+ ${repoLine}`));\n }\n } else if (inDiff) {\n // Show context lines after diff changes\n if (sysLine === repoLine && sysLine !== undefined) {\n lines.push(c.dim(` ${sysLine}`));\n }\n } else {\n // Exit diff context after matching lines\n inDiff = false;\n }\n }\n }\n\n return lines.join('\\n');\n};\n\nconst runDiff = async (paths: string[], options: DiffOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // If --staged, show git diff\n if (options.staged) {\n const diff = await getDiff(tuckDir, { staged: true, stat: options.stat });\n if (diff) {\n console.log(diff);\n } else {\n logger.info('No staged changes');\n }\n return;\n }\n\n // Get all tracked files\n const allFiles = await getAllTrackedFiles(tuckDir);\n const changedFiles: FileDiff[] = [];\n\n // If no paths specified, check all files\n const filesToCheck =\n paths.length === 0\n ? Object.values(allFiles)\n : paths.map((path) => {\n const expandedPath = expandPath(path);\n const collapsedPath = collapsePath(expandedPath);\n const tracked = Object.entries(allFiles).find(([, f]) => f.source === collapsedPath);\n if (!tracked) {\n throw new FileNotFoundError(`Not tracked: ${path}`);\n }\n return tracked[1];\n });\n\n // Check each file for changes\n for (const file of filesToCheck) {\n // Skip if category filter is set and doesn't match\n if (options.category && file.category !== options.category) {\n continue;\n }\n\n // Skip if in .tuckignore\n if (await isIgnored(tuckDir, file.source)) {\n continue;\n }\n\n try {\n const diff = await getFileDiff(tuckDir, file.source);\n if (diff && diff.hasChanges) {\n changedFiles.push(diff);\n }\n } catch (error) {\n if (error instanceof FileNotFoundError) {\n logger.warning(`File not found: ${file.source}`);\n } else if (error instanceof PermissionError) {\n logger.warning(`Permission denied: ${file.source}`);\n } else {\n throw error;\n }\n }\n }\n\n if (changedFiles.length === 0) {\n if (paths.length > 0) {\n logger.success('No differences found');\n } else {\n prompts.intro('tuck diff');\n console.log();\n logger.success('No differences found');\n console.log();\n }\n return;\n }\n\n prompts.intro('tuck diff');\n console.log();\n\n // Show stats/name-only if requested\n if (options.stat || options.nameOnly) {\n const label = options.nameOnly\n ? 'Changed files:'\n : `${changedFiles.length} file${changedFiles.length > 1 ? 's' : ''} changed:`;\n console.log(c.bold(label));\n console.log();\n\n for (const diff of changedFiles) {\n const status = diff.isDirectory ? c.dim('[dir]') : diff.isBinary ? c.dim('[bin]') : '';\n console.log(` ${c.yellow('~')} ${diff.source} ${status}`);\n }\n\n console.log();\n prompts.outro(`Found ${changedFiles.length} changed file(s)`);\n return;\n }\n\n // Show full diff for each file\n for (const diff of changedFiles) {\n console.log(formatUnifiedDiff(diff));\n console.log();\n }\n\n prompts.outro(`Found ${changedFiles.length} changed file(s)`);\n\n // Return exit code 1 if differences found and --exit-code is set\n if (options.exitCode) {\n process.exit(1);\n }\n};\n\nexport { runDiff, formatUnifiedDiff };\n\nexport const diffCommand = new Command('diff')\n .description('Show differences between system and repository')\n .argument('[paths...]', 'Specific files to diff')\n .option('--staged', 'Show staged git changes')\n .option('--stat', 'Show diffstat only')\n .option(\n '--category <category>',\n 'Filter by file category (shell, git, editors, terminal, ssh, misc)'\n )\n .option('--name-only', 'Show only changed file names')\n .option('--exit-code', 'Return exit code 1 if differences found')\n .action(async (paths: string[], options: DiffOptions) => {\n await runDiff(paths, options);\n });\n","import { Command } from 'commander';\nimport { spawn } from 'child_process';\nimport { prompts, logger, banner, colors as c } from '../ui/index.js';\nimport { getTuckDir, getConfigPath, collapsePath } from '../lib/paths.js';\nimport { loadConfig, saveConfig, resetConfig } from '../lib/config.js';\nimport { loadManifest } from '../lib/manifest.js';\nimport { NotInitializedError, ConfigError } from '../errors.js';\nimport type { TuckConfigOutput } from '../schemas/config.schema.js';\n\n/**\n * Configuration key metadata for validation and help\n */\ninterface ConfigKeyInfo {\n path: string;\n type: 'boolean' | 'string' | 'enum';\n description: string;\n section: string;\n options?: string[]; // For enum types\n}\n\nconst CONFIG_KEYS: ConfigKeyInfo[] = [\n // Repository settings\n {\n path: 'repository.defaultBranch',\n type: 'string',\n description: 'Default git branch name',\n section: 'repository',\n },\n {\n path: 'repository.autoCommit',\n type: 'boolean',\n description: 'Auto-commit changes on sync',\n section: 'repository',\n },\n {\n path: 'repository.autoPush',\n type: 'boolean',\n description: 'Auto-push after commit',\n section: 'repository',\n },\n // File settings\n {\n path: 'files.strategy',\n type: 'enum',\n description: 'File copy strategy',\n section: 'files',\n options: ['copy', 'symlink'],\n },\n {\n path: 'files.backupOnRestore',\n type: 'boolean',\n description: 'Create backups before restore',\n section: 'files',\n },\n {\n path: 'files.backupDir',\n type: 'string',\n description: 'Backup directory path',\n section: 'files',\n },\n // UI settings\n { path: 'ui.colors', type: 'boolean', description: 'Enable colored output', section: 'ui' },\n { path: 'ui.emoji', type: 'boolean', description: 'Enable emoji in output', section: 'ui' },\n { path: 'ui.verbose', type: 'boolean', description: 'Enable verbose logging', section: 'ui' },\n // Hook settings\n {\n path: 'hooks.preSync',\n type: 'string',\n description: 'Command to run before sync',\n section: 'hooks',\n },\n {\n path: 'hooks.postSync',\n type: 'string',\n description: 'Command to run after sync',\n section: 'hooks',\n },\n {\n path: 'hooks.preRestore',\n type: 'string',\n description: 'Command to run before restore',\n section: 'hooks',\n },\n {\n path: 'hooks.postRestore',\n type: 'string',\n description: 'Command to run after restore',\n section: 'hooks',\n },\n // Template settings\n {\n path: 'templates.enabled',\n type: 'boolean',\n description: 'Enable template processing',\n section: 'templates',\n },\n // Encryption settings\n {\n path: 'encryption.enabled',\n type: 'boolean',\n description: 'Enable file encryption',\n section: 'encryption',\n },\n {\n path: 'encryption.gpgKey',\n type: 'string',\n description: 'GPG key for encryption',\n section: 'encryption',\n },\n];\n\nconst getKeyInfo = (path: string): ConfigKeyInfo | undefined => {\n return CONFIG_KEYS.find((k) => k.path === path);\n};\n\nconst formatConfigValue = (value: unknown): string => {\n if (value === undefined || value === null) return c.dim('(not set)');\n if (typeof value === 'boolean') return value ? c.green('true') : c.yellow('false');\n if (Array.isArray(value)) return value.length ? c.cyan(value.join(', ')) : c.dim('[]');\n if (typeof value === 'object') return c.dim(JSON.stringify(value));\n return c.white(String(value));\n};\n\nconst printConfig = (config: TuckConfigOutput): void => {\n console.log(JSON.stringify(config, null, 2));\n};\n\nconst getNestedValue = (obj: Record<string, unknown>, path: string): unknown => {\n const keys = path.split('.');\n let current: unknown = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined;\n }\n if (typeof current !== 'object') {\n return undefined;\n }\n current = (current as Record<string, unknown>)[key];\n }\n\n return current;\n};\n\nconst setNestedValue = (obj: Record<string, unknown>, path: string, value: unknown): void => {\n const keys = path.split('.');\n let current = obj;\n\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i];\n if (!(key in current) || typeof current[key] !== 'object') {\n current[key] = {};\n }\n current = current[key] as Record<string, unknown>;\n }\n\n current[keys[keys.length - 1]] = value;\n};\n\nconst parseValue = (value: string): unknown => {\n // Try to parse as JSON\n try {\n return JSON.parse(value);\n } catch {\n // Return as string if not valid JSON\n return value;\n }\n};\n\nconst runConfigGet = async (key: string): Promise<void> => {\n const tuckDir = getTuckDir();\n const config = await loadConfig(tuckDir);\n\n const value = getNestedValue(config as unknown as Record<string, unknown>, key);\n\n if (value === undefined) {\n logger.error(`Key not found: ${key}`);\n return;\n }\n\n if (typeof value === 'object') {\n console.log(JSON.stringify(value, null, 2));\n } else {\n console.log(value);\n }\n};\n\nconst runConfigSet = async (key: string, value: string): Promise<void> => {\n const tuckDir = getTuckDir();\n const config = await loadConfig(tuckDir);\n\n const parsedValue = parseValue(value);\n const configObj = config as unknown as Record<string, unknown>;\n\n setNestedValue(configObj, key, parsedValue);\n\n await saveConfig(config, tuckDir);\n logger.success(`Set ${key} = ${JSON.stringify(parsedValue)}`);\n};\n\nconst runConfigList = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n const config = await loadConfig(tuckDir);\n\n prompts.intro('tuck config');\n console.log();\n console.log(c.dim('Configuration file:'), collapsePath(getConfigPath(tuckDir)));\n console.log();\n\n printConfig(config);\n};\n\nconst runConfigEdit = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n const configPath = getConfigPath(tuckDir);\n\n const editor = process.env.EDITOR || process.env.VISUAL || 'vim';\n\n logger.info(`Opening ${collapsePath(configPath)} in ${editor}...`);\n\n return new Promise((resolve, reject) => {\n const child = spawn(editor, [configPath], {\n stdio: 'inherit',\n });\n\n child.on('exit', (code) => {\n if (code === 0) {\n logger.success('Configuration updated');\n resolve();\n } else {\n reject(new ConfigError(`Editor exited with code ${code}`));\n }\n });\n\n child.on('error', (err) => {\n reject(new ConfigError(`Failed to open editor: ${err.message}`));\n });\n });\n};\n\nconst runConfigReset = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n\n const confirm = await prompts.confirm(\n 'Reset configuration to defaults? This cannot be undone.',\n false\n );\n\n if (!confirm) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n await resetConfig(tuckDir);\n logger.success('Configuration reset to defaults');\n};\n\n/**\n * Show configuration in a visually organized way\n */\nconst showConfigView = async (config: TuckConfigOutput): Promise<void> => {\n const configObj = config as unknown as Record<string, unknown>;\n\n const sections = [\n { key: 'repository', title: 'Repository Settings', icon: '*' },\n { key: 'files', title: 'File Management', icon: '>' },\n { key: 'ui', title: 'User Interface', icon: '#' },\n { key: 'hooks', title: 'Hooks', icon: '!' },\n { key: 'templates', title: 'Templates', icon: '%' },\n { key: 'encryption', title: 'Encryption', icon: '@' },\n ];\n\n for (const section of sections) {\n const sectionConfig = configObj[section.key];\n if (!sectionConfig || typeof sectionConfig !== 'object') continue;\n\n console.log(c.bold.cyan(`${section.icon} ${section.title}`));\n console.log(c.dim('-'.repeat(40)));\n\n for (const [key, value] of Object.entries(sectionConfig as Record<string, unknown>)) {\n const keyInfo = getKeyInfo(`${section.key}.${key}`);\n const displayValue = formatConfigValue(value);\n const description = keyInfo?.description || '';\n\n console.log(` ${c.white(key)}: ${displayValue}`);\n if (description) {\n console.log(c.dim(` ${description}`));\n }\n }\n console.log();\n }\n};\n\n/**\n * Run configuration wizard for guided setup\n */\nconst runConfigWizard = async (config: TuckConfigOutput, tuckDir: string): Promise<void> => {\n prompts.log.info(\"Let's configure tuck for your workflow\");\n console.log();\n\n // Repository behavior\n console.log(c.bold.cyan('* Repository Behavior'));\n const autoCommit = await prompts.confirm(\n 'Auto-commit changes when running sync?',\n config.repository.autoCommit ?? true\n );\n const autoPush = await prompts.confirm(\n 'Auto-push to remote after commit?',\n config.repository.autoPush ?? false\n );\n\n // File strategy\n console.log();\n console.log(c.bold.cyan('> File Strategy'));\n const rawStrategy = await prompts.select('How should tuck manage files?', [\n { value: 'copy', label: 'Copy files', hint: 'Safe, independent copies' },\n { value: 'symlink', label: 'Symlink files', hint: 'Real-time updates, single source of truth' },\n ]);\n const strategy: 'copy' | 'symlink' =\n rawStrategy === 'copy' || rawStrategy === 'symlink'\n ? rawStrategy\n : (config.files.strategy ?? 'copy');\n\n const backupOnRestore = await prompts.confirm(\n 'Create backups before restoring files?',\n config.files.backupOnRestore ?? true\n );\n\n // UI preferences\n console.log();\n console.log(c.bold.cyan('# User Interface'));\n const colors = await prompts.confirm('Enable colored output?', config.ui.colors ?? true);\n const emoji = await prompts.confirm('Enable emoji in output?', config.ui.emoji ?? true);\n const verbose = await prompts.confirm('Enable verbose logging?', config.ui.verbose ?? false);\n\n // Apply changes\n const updatedConfig: TuckConfigOutput = {\n ...config,\n repository: {\n ...config.repository,\n autoCommit,\n autoPush,\n },\n files: {\n ...config.files,\n strategy,\n backupOnRestore,\n },\n ui: {\n colors,\n emoji,\n verbose,\n },\n };\n\n await saveConfig(updatedConfig, tuckDir);\n\n console.log();\n prompts.log.success('Configuration updated!');\n prompts.note(\"Run 'tuck config' again to view or edit settings\", 'Tip');\n};\n\n/**\n * Interactive edit a single setting\n */\nconst editConfigInteractive = async (config: TuckConfigOutput, tuckDir: string): Promise<void> => {\n const configObj = config as unknown as Record<string, unknown>;\n\n // Create options for selection\n const options = CONFIG_KEYS.map((key) => {\n const currentValue = getNestedValue(configObj, key.path);\n return {\n value: key.path,\n label: key.path,\n hint: `${key.description} (current: ${formatConfigValue(currentValue)})`,\n };\n });\n\n const selectedKey = (await prompts.select('Select setting to edit:', options)) as string;\n const keyInfo = getKeyInfo(selectedKey);\n const currentValue = getNestedValue(configObj, selectedKey);\n\n if (!keyInfo) {\n logger.error(`Unknown key: ${selectedKey}`);\n return;\n }\n\n let newValue: unknown;\n\n switch (keyInfo.type) {\n case 'boolean': {\n const defaultValue = typeof currentValue === 'boolean' ? currentValue : false;\n newValue = await prompts.confirm(keyInfo.description, defaultValue);\n break;\n }\n case 'enum':\n newValue = await prompts.select(\n `Select value for ${selectedKey}:`,\n (keyInfo.options || []).map((opt) => ({ value: opt, label: opt }))\n );\n break;\n case 'string':\n newValue = await prompts.text(`Enter value for ${selectedKey}:`, {\n defaultValue: (currentValue as string) || '',\n placeholder: '(leave empty to clear)',\n });\n break;\n }\n\n setNestedValue(configObj, selectedKey, newValue);\n await saveConfig(config, tuckDir);\n\n prompts.log.success(`Updated ${selectedKey} = ${formatConfigValue(newValue)}`);\n};\n\n/**\n * Run interactive config mode\n */\nconst runInteractiveConfig = async (): Promise<void> => {\n banner();\n prompts.intro('tuck config');\n\n const tuckDir = getTuckDir();\n const config = await loadConfig(tuckDir);\n\n const action = (await prompts.select('What would you like to do?', [\n { value: 'view', label: 'View current configuration', hint: 'See all settings' },\n { value: 'edit', label: 'Edit a setting', hint: 'Modify a specific value' },\n { value: 'wizard', label: 'Run setup wizard', hint: 'Guided configuration' },\n { value: 'reset', label: 'Reset to defaults', hint: 'Restore default values' },\n { value: 'open', label: 'Open in editor', hint: `Edit with ${process.env.EDITOR || 'vim'}` },\n ])) as string;\n\n console.log();\n\n switch (action) {\n case 'view':\n await showConfigView(config);\n break;\n case 'edit':\n await editConfigInteractive(config, tuckDir);\n break;\n case 'wizard':\n await runConfigWizard(config, tuckDir);\n break;\n case 'reset':\n await runConfigReset();\n break;\n case 'open':\n await runConfigEdit();\n break;\n }\n\n prompts.outro('Done!');\n};\n\nexport const configCommand = new Command('config')\n .description('Manage tuck configuration')\n .action(async () => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runInteractiveConfig();\n })\n .addCommand(\n new Command('get')\n .description('Get a config value')\n .argument('<key>', 'Config key (e.g., \"repository.autoCommit\")')\n .action(async (key: string) => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runConfigGet(key);\n })\n )\n .addCommand(\n new Command('set')\n .description('Set a config value')\n .argument('<key>', 'Config key')\n .argument('<value>', 'Value to set (JSON or string)')\n .action(async (key: string, value: string) => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runConfigSet(key, value);\n })\n )\n .addCommand(\n new Command('list').description('List all config').action(async () => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runConfigList();\n })\n )\n .addCommand(\n new Command('edit').description('Open config in editor').action(async () => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runConfigEdit();\n })\n )\n .addCommand(\n new Command('reset').description('Reset to defaults').action(async () => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runConfigReset();\n })\n );\n","import { Command } from 'commander';\nimport { join } from 'path';\nimport { readFile, rm, chmod, stat } from 'fs/promises';\nimport { ensureDir, pathExists as fsPathExists } from 'fs-extra';\nimport { tmpdir } from 'os';\nimport { banner, prompts, logger, colors as c } from '../ui/index.js';\nimport { expandPath, pathExists, collapsePath, validateSafeSourcePath } from '../lib/paths.js';\nimport { cloneRepo } from '../lib/git.js';\nimport { isGhInstalled, findDotfilesRepo, ghCloneRepo, repoExists } from '../lib/github.js';\nimport { createPreApplySnapshot } from '../lib/timemachine.js';\nimport { smartMerge, isShellFile, generateMergePreview } from '../lib/merge.js';\nimport { copyFileOrDir } from '../lib/files.js';\nimport { CATEGORIES } from '../constants.js';\nimport type { TuckManifest } from '../types.js';\nimport { findPlaceholders } from '../lib/secrets/index.js';\n\n/**\n * Fix permissions for SSH/GPG files after apply\n */\nconst fixSecurePermissions = async (path: string): Promise<void> => {\n const collapsedPath = collapsePath(path);\n\n // Only fix permissions for SSH and GPG files\n if (!collapsedPath.includes('.ssh/') && !collapsedPath.includes('.gnupg/')) {\n return;\n }\n\n try {\n const stats = await stat(path);\n\n if (stats.isDirectory()) {\n await chmod(path, 0o700);\n } else {\n await chmod(path, 0o600);\n }\n } catch {\n // Ignore permission errors (might be on Windows)\n }\n};\n\nexport interface ApplyOptions {\n merge?: boolean;\n replace?: boolean;\n dryRun?: boolean;\n force?: boolean;\n yes?: boolean;\n}\n\ninterface ApplyFile {\n source: string;\n destination: string;\n category: string;\n repoPath: string;\n}\n\ninterface ApplyResult {\n appliedCount: number;\n filesWithPlaceholders: Array<{\n path: string;\n placeholders: string[];\n }>;\n}\n\n/**\n * Resolve a source (username or repo URL) to a full repository identifier\n */\nconst resolveSource = async (source: string): Promise<{ repoId: string; isUrl: boolean }> => {\n // Check if it's a full URL\n if (source.includes('://') || source.startsWith('git@')) {\n return { repoId: source, isUrl: true };\n }\n\n // Check if it's a GitHub repo identifier (user/repo)\n if (source.includes('/')) {\n return { repoId: source, isUrl: false };\n }\n\n // Assume it's a username, try to find their dotfiles repo\n logger.info(`Looking for dotfiles repository for ${source}...`);\n\n if (await isGhInstalled()) {\n const dotfilesRepo = await findDotfilesRepo(source);\n if (dotfilesRepo) {\n logger.success(`Found repository: ${dotfilesRepo}`);\n return { repoId: dotfilesRepo, isUrl: false };\n }\n }\n\n // Try common repo names\n const commonNames = ['dotfiles', 'tuck', '.dotfiles'];\n for (const name of commonNames) {\n const repoId = `${source}/${name}`;\n if (await repoExists(repoId)) {\n logger.success(`Found repository: ${repoId}`);\n return { repoId, isUrl: false };\n }\n }\n\n throw new Error(\n `Could not find a dotfiles repository for \"${source}\". ` +\n 'Try specifying the full repository name (e.g., username/dotfiles)'\n );\n};\n\n/**\n * Clone the source repository to a temporary directory\n */\nconst cloneSource = async (repoId: string, isUrl: boolean): Promise<string> => {\n const tempDir = join(tmpdir(), `tuck-apply-${Date.now()}`);\n await ensureDir(tempDir);\n\n if (isUrl) {\n await cloneRepo(repoId, tempDir);\n } else {\n // Use gh CLI to clone if available, otherwise construct URL\n if (await isGhInstalled()) {\n await ghCloneRepo(repoId, tempDir);\n } else {\n const url = `https://github.com/${repoId}.git`;\n await cloneRepo(url, tempDir);\n }\n }\n\n return tempDir;\n};\n\n/**\n * Read the manifest from a cloned repository\n */\nconst readClonedManifest = async (repoDir: string): Promise<TuckManifest | null> => {\n const manifestPath = join(repoDir, '.tuckmanifest.json');\n\n if (!(await fsPathExists(manifestPath))) {\n return null;\n }\n\n try {\n const content = await readFile(manifestPath, 'utf-8');\n return JSON.parse(content) as TuckManifest;\n } catch {\n return null;\n }\n};\n\n/**\n * Prepare the list of files to apply\n */\nconst prepareFilesToApply = async (\n repoDir: string,\n manifest: TuckManifest\n): Promise<ApplyFile[]> => {\n const files: ApplyFile[] = [];\n\n for (const [_id, file] of Object.entries(manifest.files)) {\n const repoFilePath = join(repoDir, file.destination);\n\n if (await fsPathExists(repoFilePath)) {\n // Validate that the source path is safe (within home directory)\n // This prevents malicious manifests from writing to arbitrary locations\n try {\n validateSafeSourcePath(file.source);\n } catch (error) {\n logger.warning(`Skipping unsafe path from manifest: ${file.source}`);\n continue;\n }\n\n files.push({\n source: file.source,\n destination: expandPath(file.source),\n category: file.category,\n repoPath: repoFilePath,\n });\n }\n }\n\n return files;\n};\n\n/**\n * Apply files with merge strategy\n */\nconst applyWithMerge = async (files: ApplyFile[], dryRun: boolean): Promise<ApplyResult> => {\n const result: ApplyResult = {\n appliedCount: 0,\n filesWithPlaceholders: [],\n };\n\n for (const file of files) {\n const fileContent = await readFile(file.repoPath, 'utf-8');\n\n // Check for placeholders that need secret values\n const placeholders = findPlaceholders(fileContent);\n if (placeholders.length > 0) {\n result.filesWithPlaceholders.push({\n path: collapsePath(file.destination),\n placeholders,\n });\n }\n\n if (isShellFile(file.source) && (await pathExists(file.destination))) {\n // Use smart merge for shell files\n const mergeResult = await smartMerge(file.destination, fileContent);\n\n if (dryRun) {\n logger.file(\n 'merge',\n `${collapsePath(file.destination)} (${mergeResult.preservedBlocks} blocks preserved)`\n );\n } else {\n const { writeFile } = await import('fs/promises');\n const { ensureDir } = await import('fs-extra');\n const { dirname } = await import('path');\n\n await ensureDir(dirname(file.destination));\n await writeFile(file.destination, mergeResult.content, 'utf-8');\n logger.file('merge', collapsePath(file.destination));\n }\n } else {\n // Copy non-shell files directly\n if (dryRun) {\n if (await pathExists(file.destination)) {\n logger.file('modify', collapsePath(file.destination));\n } else {\n logger.file('add', collapsePath(file.destination));\n }\n } else {\n const fileExists = await pathExists(file.destination);\n await copyFileOrDir(file.repoPath, file.destination, { overwrite: true });\n await fixSecurePermissions(file.destination);\n logger.file(fileExists ? 'modify' : 'add', collapsePath(file.destination));\n }\n }\n\n result.appliedCount++;\n }\n\n return result;\n};\n\n/**\n * Apply files with replace strategy\n */\nconst applyWithReplace = async (files: ApplyFile[], dryRun: boolean): Promise<ApplyResult> => {\n const result: ApplyResult = {\n appliedCount: 0,\n filesWithPlaceholders: [],\n };\n\n for (const file of files) {\n // Check for placeholders that need secret values\n const fileContent = await readFile(file.repoPath, 'utf-8');\n const placeholders = findPlaceholders(fileContent);\n if (placeholders.length > 0) {\n result.filesWithPlaceholders.push({\n path: collapsePath(file.destination),\n placeholders,\n });\n }\n\n if (dryRun) {\n if (await pathExists(file.destination)) {\n logger.file('modify', `${collapsePath(file.destination)} (replace)`);\n } else {\n logger.file('add', collapsePath(file.destination));\n }\n } else {\n const fileExists = await pathExists(file.destination);\n await copyFileOrDir(file.repoPath, file.destination, { overwrite: true });\n await fixSecurePermissions(file.destination);\n logger.file(fileExists ? 'modify' : 'add', collapsePath(file.destination));\n }\n\n result.appliedCount++;\n }\n\n return result;\n};\n\n/**\n * Display warnings for files with unresolved placeholders\n */\nconst displayPlaceholderWarnings = (\n filesWithPlaceholders: ApplyResult['filesWithPlaceholders']\n): void => {\n if (filesWithPlaceholders.length === 0) return;\n\n console.log();\n console.log(c.yellow('⚠ Warning: Some files contain unresolved placeholders:'));\n console.log();\n\n for (const { path, placeholders } of filesWithPlaceholders) {\n console.log(c.dim(` ${path}:`));\n\n const maxToShow = 5;\n if (placeholders.length <= maxToShow) {\n // For small numbers, show all placeholders\n for (const placeholder of placeholders) {\n console.log(c.yellow(` {{${placeholder}}}`));\n }\n } else {\n // For larger numbers, show a sampling: first 3 and last 2\n const firstCount = 3;\n const lastCount = 2;\n const firstPlaceholders = placeholders.slice(0, firstCount);\n const lastPlaceholders = placeholders.slice(-lastCount);\n\n for (const placeholder of firstPlaceholders) {\n console.log(c.yellow(` {{${placeholder}}}`));\n }\n\n // Indicate that some placeholders are omitted in the middle\n console.log(c.dim(' ...'));\n\n for (const placeholder of lastPlaceholders) {\n console.log(c.yellow(` {{${placeholder}}}`));\n }\n\n const shownCount = firstPlaceholders.length + lastPlaceholders.length;\n const hiddenCount = placeholders.length - shownCount;\n if (hiddenCount > 0) {\n console.log(c.dim(` ... and ${hiddenCount} more not shown`));\n }\n }\n }\n\n console.log();\n console.log(c.dim(' These placeholders need to be replaced with actual values.'));\n console.log(c.dim(' Use `tuck secrets set <NAME> <value>` to configure secrets,'));\n console.log(c.dim(' then re-apply to populate them.'));\n};\n\n/**\n * Run interactive apply flow\n */\nconst runInteractiveApply = async (source: string, options: ApplyOptions): Promise<void> => {\n banner();\n prompts.intro('tuck apply');\n\n // Resolve the source\n let repoId: string;\n let isUrl: boolean;\n\n try {\n const resolved = await resolveSource(source);\n repoId = resolved.repoId;\n isUrl = resolved.isUrl;\n } catch (error) {\n prompts.log.error(error instanceof Error ? error.message : String(error));\n return;\n }\n\n // Clone the repository\n let repoDir: string;\n try {\n const spinner = prompts.spinner();\n spinner.start('Cloning repository...');\n repoDir = await cloneSource(repoId, isUrl);\n spinner.stop('Repository cloned');\n } catch (error) {\n prompts.log.error(`Failed to clone: ${error instanceof Error ? error.message : String(error)}`);\n return;\n }\n\n try {\n // Read the manifest\n const manifest = await readClonedManifest(repoDir);\n\n if (!manifest) {\n prompts.log.error('No tuck manifest found in repository');\n prompts.note(\n 'This repository may not be managed by tuck.\\nLook for a .tuckmanifest.json file.',\n 'Tip'\n );\n return;\n }\n\n // Prepare files to apply\n const files = await prepareFilesToApply(repoDir, manifest);\n\n if (files.length === 0) {\n prompts.log.warning('No files to apply');\n return;\n }\n\n // Show what will be applied\n prompts.log.info(`Found ${files.length} file(s) to apply:`);\n console.log();\n\n // Group by category\n const byCategory: Record<string, ApplyFile[]> = {};\n for (const file of files) {\n if (!byCategory[file.category]) {\n byCategory[file.category] = [];\n }\n byCategory[file.category].push(file);\n }\n\n for (const [category, categoryFiles] of Object.entries(byCategory)) {\n const categoryConfig = CATEGORIES[category] || { icon: '📄' };\n console.log(c.bold(` ${categoryConfig.icon} ${category}`));\n for (const file of categoryFiles) {\n const exists = await pathExists(file.destination);\n const status = exists ? c.yellow('(will update)') : c.green('(new)');\n console.log(c.dim(` ${collapsePath(file.destination)} ${status}`));\n }\n }\n console.log();\n\n // Ask for merge strategy\n let strategy: 'merge' | 'replace';\n\n if (options.merge) {\n strategy = 'merge';\n } else if (options.replace) {\n strategy = 'replace';\n } else {\n strategy = await prompts.select('How should conflicts be handled?', [\n {\n value: 'merge',\n label: 'Merge (recommended)',\n hint: 'Preserve local customizations marked with # local or # tuck:preserve',\n },\n {\n value: 'replace',\n label: 'Replace',\n hint: 'Overwrite all files completely',\n },\n ]);\n }\n\n // Show merge preview for shell files if using merge strategy\n if (strategy === 'merge') {\n const shellFiles = files.filter((f) => isShellFile(f.source));\n if (shellFiles.length > 0) {\n console.log();\n for (const file of shellFiles.slice(0, 3)) {\n if (await pathExists(file.destination)) {\n const fileContent = await readFile(file.repoPath, 'utf-8');\n const preview = await generateMergePreview(file.destination, fileContent);\n prompts.note(preview, collapsePath(file.destination));\n }\n }\n if (shellFiles.length > 3) {\n prompts.log.info(`... and ${shellFiles.length - 3} more shell files`);\n }\n }\n }\n\n // Confirm\n if (!options.yes && !options.force) {\n console.log();\n const confirmed = await prompts.confirm(\n `Apply ${files.length} files using ${strategy} strategy?`,\n true\n );\n\n if (!confirmed) {\n prompts.cancel('Apply cancelled');\n return;\n }\n }\n\n // Create Time Machine backup before applying\n // Note: We need to properly await async checks - Array.filter doesn't await promises\n const existingPaths = [];\n for (const file of files) {\n if (await pathExists(file.destination)) {\n existingPaths.push(file.destination);\n }\n }\n\n if (existingPaths.length > 0 && !options.dryRun) {\n const spinner = prompts.spinner();\n spinner.start('Creating backup snapshot...');\n const snapshot = await createPreApplySnapshot(existingPaths, repoId);\n spinner.stop(`Backup created: ${snapshot.id}`);\n console.log();\n }\n\n // Apply files\n if (options.dryRun) {\n prompts.log.info('Dry run - no changes will be made:');\n } else {\n prompts.log.info('Applying files...');\n }\n console.log();\n\n let applyResult: ApplyResult;\n if (strategy === 'merge') {\n applyResult = await applyWithMerge(files, options.dryRun || false);\n } else {\n applyResult = await applyWithReplace(files, options.dryRun || false);\n }\n\n console.log();\n\n if (options.dryRun) {\n prompts.log.info(`Would apply ${applyResult.appliedCount} files`);\n } else {\n prompts.log.success(`Applied ${applyResult.appliedCount} files`);\n }\n\n // Show placeholder warnings\n displayPlaceholderWarnings(applyResult.filesWithPlaceholders);\n\n if (!options.dryRun) {\n console.log();\n prompts.note(\n 'To undo this apply, run:\\n tuck restore --latest\\n\\nTo see all backups:\\n tuck restore --list',\n 'Undo'\n );\n }\n\n prompts.outro('Done!');\n } finally {\n // Clean up temp directory\n try {\n await rm(repoDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n};\n\n/**\n * Run non-interactive apply\n */\nconst runApply = async (source: string, options: ApplyOptions): Promise<void> => {\n // Resolve the source\n const { repoId, isUrl } = await resolveSource(source);\n\n // Clone the repository\n logger.info('Cloning repository...');\n const repoDir = await cloneSource(repoId, isUrl);\n\n try {\n // Read the manifest\n const manifest = await readClonedManifest(repoDir);\n\n if (!manifest) {\n throw new Error('No tuck manifest found in repository');\n }\n\n // Prepare files to apply\n const files = await prepareFilesToApply(repoDir, manifest);\n\n if (files.length === 0) {\n logger.warning('No files to apply');\n return;\n }\n\n // Determine strategy\n const strategy = options.replace ? 'replace' : 'merge';\n\n // Create backup if not dry run\n if (!options.dryRun) {\n const existingPaths = [];\n for (const file of files) {\n if (await pathExists(file.destination)) {\n existingPaths.push(file.destination);\n }\n }\n\n if (existingPaths.length > 0) {\n logger.info('Creating backup snapshot...');\n const snapshot = await createPreApplySnapshot(existingPaths, repoId);\n logger.success(`Backup created: ${snapshot.id}`);\n }\n }\n\n // Apply files\n if (options.dryRun) {\n logger.heading('Dry run - would apply:');\n } else {\n logger.heading('Applying:');\n }\n\n let applyResult: ApplyResult;\n if (strategy === 'merge') {\n applyResult = await applyWithMerge(files, options.dryRun || false);\n } else {\n applyResult = await applyWithReplace(files, options.dryRun || false);\n }\n\n logger.blank();\n\n if (options.dryRun) {\n logger.info(`Would apply ${applyResult.appliedCount} files`);\n } else {\n logger.success(`Applied ${applyResult.appliedCount} files`);\n }\n\n // Show placeholder warnings\n displayPlaceholderWarnings(applyResult.filesWithPlaceholders);\n\n if (!options.dryRun) {\n logger.info('To undo: tuck restore --latest');\n }\n } finally {\n // Clean up temp directory\n try {\n await rm(repoDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n};\n\nexport const applyCommand = new Command('apply')\n .description('Apply dotfiles from a repository to this machine')\n .argument('<source>', 'GitHub username, user/repo, or full repository URL')\n .option('-m, --merge', 'Merge with existing files (preserve local customizations)')\n .option('-r, --replace', 'Replace existing files completely')\n .option('--dry-run', 'Show what would be applied without making changes')\n .option('-f, --force', 'Apply without confirmation prompts')\n .option('-y, --yes', 'Assume yes to all prompts')\n .action(async (source: string, options: ApplyOptions) => {\n // Determine if we should run interactive mode\n const isInteractive = !options.force && !options.yes && process.stdout.isTTY;\n\n if (isInteractive) {\n await runInteractiveApply(source, options);\n } else {\n await runApply(source, options);\n }\n });\n","import { join, dirname } from 'path';\nimport { readdir, readFile, writeFile, rm, stat } from 'fs/promises';\nimport { copy, ensureDir, pathExists } from 'fs-extra';\nimport { homedir } from 'os';\nimport { expandPath, collapsePath, pathExists as checkPathExists } from './paths.js';\nimport { BackupError } from '../errors.js';\n\nconst TIMEMACHINE_DIR = join(homedir(), '.tuck', 'backups');\n\nexport interface SnapshotMetadata {\n id: string;\n timestamp: string;\n reason: string;\n files: SnapshotFile[];\n machine: string;\n profile?: string;\n}\n\nexport interface SnapshotFile {\n originalPath: string;\n backupPath: string;\n existed: boolean;\n}\n\nexport interface Snapshot {\n id: string;\n path: string;\n timestamp: Date;\n reason: string;\n files: SnapshotFile[];\n machine: string;\n profile?: string;\n}\n\n/**\n * Generate a unique snapshot ID (YYYY-MM-DD-HHMMSS)\n */\nconst generateSnapshotId = (): string => {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n const hours = String(now.getHours()).padStart(2, '0');\n const minutes = String(now.getMinutes()).padStart(2, '0');\n const seconds = String(now.getSeconds()).padStart(2, '0');\n return `${year}-${month}-${day}-${hours}${minutes}${seconds}`;\n};\n\n/**\n * Get the path to a snapshot directory\n */\nconst getSnapshotPath = (snapshotId: string): string => {\n return join(TIMEMACHINE_DIR, snapshotId);\n};\n\n/**\n * Convert original path to a safe backup path, preserving directory structure\n * to prevent filename collisions. The path is relative to the backup files directory.\n * e.g., ~/.zshrc -> .zshrc\n * e.g., ~/.config/nvim -> .config/nvim\n * e.g., ~/.foo.bar -> .foo.bar (distinct from ~/.foo-bar -> .foo-bar)\n */\nconst toBackupPath = (originalPath: string): string => {\n const collapsed = collapsePath(originalPath);\n // Remove ~/ prefix to get a path relative to home directory\n // This preserves the full directory structure, preventing collisions\n return collapsed.replace(/^~\\//, '');\n};\n\n/**\n * Create a Time Machine snapshot of multiple files\n * This is the main entry point for creating backups before apply operations\n */\nexport const createSnapshot = async (\n filePaths: string[],\n reason: string,\n profile?: string\n): Promise<Snapshot> => {\n const snapshotId = generateSnapshotId();\n const snapshotPath = getSnapshotPath(snapshotId);\n\n await ensureDir(snapshotPath);\n\n const files: SnapshotFile[] = [];\n const machine = (await import('os')).hostname();\n\n for (const filePath of filePaths) {\n const expandedPath = expandPath(filePath);\n const backupRelativePath = toBackupPath(expandedPath);\n const backupPath = join(snapshotPath, 'files', backupRelativePath);\n\n const existed = await checkPathExists(expandedPath);\n\n if (existed) {\n await ensureDir(dirname(backupPath));\n await copy(expandedPath, backupPath, { overwrite: true, preserveTimestamps: true });\n }\n\n files.push({\n originalPath: expandedPath,\n backupPath,\n existed,\n });\n }\n\n // Save metadata\n const metadata: SnapshotMetadata = {\n id: snapshotId,\n timestamp: new Date().toISOString(),\n reason,\n files,\n machine,\n profile,\n };\n\n await writeFile(\n join(snapshotPath, 'metadata.json'),\n JSON.stringify(metadata, null, 2),\n 'utf-8'\n );\n\n return {\n id: snapshotId,\n path: snapshotPath,\n timestamp: new Date(metadata.timestamp),\n reason,\n files,\n machine,\n profile,\n };\n};\n\n/**\n * Create a snapshot of the user's current dotfiles before applying new ones\n */\nexport const createPreApplySnapshot = async (\n targetPaths: string[],\n sourceRepo?: string\n): Promise<Snapshot> => {\n const reason = sourceRepo\n ? `Pre-apply backup before applying from ${sourceRepo}`\n : 'Pre-apply backup';\n\n return createSnapshot(targetPaths, reason);\n};\n\n/**\n * List all available snapshots\n */\nexport const listSnapshots = async (): Promise<Snapshot[]> => {\n if (!(await pathExists(TIMEMACHINE_DIR))) {\n return [];\n }\n\n const entries = await readdir(TIMEMACHINE_DIR, { withFileTypes: true });\n const snapshots: Snapshot[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const snapshotPath = join(TIMEMACHINE_DIR, entry.name);\n const metadataPath = join(snapshotPath, 'metadata.json');\n\n if (!(await pathExists(metadataPath))) continue;\n\n try {\n const content = await readFile(metadataPath, 'utf-8');\n const metadata: SnapshotMetadata = JSON.parse(content);\n\n snapshots.push({\n id: metadata.id,\n path: snapshotPath,\n timestamp: new Date(metadata.timestamp),\n reason: metadata.reason,\n files: metadata.files,\n machine: metadata.machine,\n profile: metadata.profile,\n });\n } catch {\n // Skip invalid snapshots\n }\n }\n\n // Sort by timestamp, newest first\n return snapshots.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n};\n\n/**\n * Get a specific snapshot by ID\n */\nexport const getSnapshot = async (snapshotId: string): Promise<Snapshot | null> => {\n const snapshotPath = getSnapshotPath(snapshotId);\n\n if (!(await pathExists(snapshotPath))) {\n return null;\n }\n\n const metadataPath = join(snapshotPath, 'metadata.json');\n\n if (!(await pathExists(metadataPath))) {\n return null;\n }\n\n try {\n const content = await readFile(metadataPath, 'utf-8');\n const metadata: SnapshotMetadata = JSON.parse(content);\n\n return {\n id: metadata.id,\n path: snapshotPath,\n timestamp: new Date(metadata.timestamp),\n reason: metadata.reason,\n files: metadata.files,\n machine: metadata.machine,\n profile: metadata.profile,\n };\n } catch {\n return null;\n }\n};\n\n/**\n * Get the latest snapshot\n */\nexport const getLatestSnapshot = async (): Promise<Snapshot | null> => {\n const snapshots = await listSnapshots();\n return snapshots.length > 0 ? snapshots[0] : null;\n};\n\n/**\n * Restore all files from a snapshot\n */\nexport const restoreSnapshot = async (snapshotId: string): Promise<string[]> => {\n const snapshot = await getSnapshot(snapshotId);\n\n if (!snapshot) {\n throw new BackupError(`Snapshot not found: ${snapshotId}`, [\n 'Run `tuck restore --list` to see available snapshots',\n ]);\n }\n\n const restoredFiles: string[] = [];\n\n for (const file of snapshot.files) {\n if (!file.existed) {\n // File didn't exist before, delete it if it exists now\n if (await checkPathExists(file.originalPath)) {\n await rm(file.originalPath, { recursive: true });\n }\n continue;\n }\n\n // Restore the backup\n if (await pathExists(file.backupPath)) {\n await ensureDir(dirname(file.originalPath));\n await copy(file.backupPath, file.originalPath, { overwrite: true, preserveTimestamps: true });\n restoredFiles.push(file.originalPath);\n }\n }\n\n return restoredFiles;\n};\n\n/**\n * Restore a single file from a snapshot\n */\nexport const restoreFileFromSnapshot = async (\n snapshotId: string,\n filePath: string\n): Promise<boolean> => {\n const snapshot = await getSnapshot(snapshotId);\n\n if (!snapshot) {\n throw new BackupError(`Snapshot not found: ${snapshotId}`);\n }\n\n const expandedPath = expandPath(filePath);\n const file = snapshot.files.find((f) => f.originalPath === expandedPath);\n\n if (!file) {\n throw new BackupError(`File not found in snapshot: ${filePath}`, [\n 'This file was not included in the snapshot',\n ]);\n }\n\n if (!file.existed) {\n // File didn't exist before, delete it if it exists now\n if (await checkPathExists(file.originalPath)) {\n await rm(file.originalPath, { recursive: true });\n }\n return true;\n }\n\n if (!(await pathExists(file.backupPath))) {\n throw new BackupError(`Backup file is missing: ${file.backupPath}`);\n }\n\n await ensureDir(dirname(file.originalPath));\n await copy(file.backupPath, file.originalPath, { overwrite: true, preserveTimestamps: true });\n return true;\n};\n\n/**\n * Delete a snapshot\n */\nexport const deleteSnapshot = async (snapshotId: string): Promise<void> => {\n const snapshotPath = getSnapshotPath(snapshotId);\n\n if (await pathExists(snapshotPath)) {\n await rm(snapshotPath, { recursive: true });\n }\n};\n\n/**\n * Clean up old snapshots, keeping only the specified number\n */\nexport const cleanOldSnapshots = async (keepCount: number): Promise<number> => {\n const snapshots = await listSnapshots();\n\n if (snapshots.length <= keepCount) {\n return 0;\n }\n\n const toDelete = snapshots.slice(keepCount);\n let deletedCount = 0;\n\n for (const snapshot of toDelete) {\n await deleteSnapshot(snapshot.id);\n deletedCount++;\n }\n\n return deletedCount;\n};\n\n/**\n * Get the total size of all snapshots in bytes\n */\nexport const getSnapshotsSize = async (): Promise<number> => {\n if (!(await pathExists(TIMEMACHINE_DIR))) {\n return 0;\n }\n\n let totalSize = 0;\n\n const calculateDirSize = async (dirPath: string): Promise<number> => {\n let size = 0;\n const entries = await readdir(dirPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = join(dirPath, entry.name);\n if (entry.isDirectory()) {\n size += await calculateDirSize(entryPath);\n } else {\n const stats = await stat(entryPath);\n size += stats.size;\n }\n }\n\n return size;\n };\n\n totalSize = await calculateDirSize(TIMEMACHINE_DIR);\n return totalSize;\n};\n\n/**\n * Format bytes to human readable string\n */\nexport const formatSnapshotSize = (bytes: number): string => {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n};\n\n/**\n * Format a snapshot ID to a human-readable date string\n */\nexport const formatSnapshotDate = (snapshotId: string): string => {\n // Parse YYYY-MM-DD-HHMMSS format\n const match = snapshotId.match(/^(\\d{4})-(\\d{2})-(\\d{2})-(\\d{2})(\\d{2})(\\d{2})$/);\n if (!match) return snapshotId;\n\n const [, year, month, day, hours, minutes, seconds] = match;\n const date = new Date(\n parseInt(year),\n parseInt(month) - 1,\n parseInt(day),\n parseInt(hours),\n parseInt(minutes),\n parseInt(seconds)\n );\n\n return date.toLocaleString();\n};\n","import { readFile } from 'fs/promises';\nimport { expandPath, pathExists } from './paths.js';\n\n/**\n * Markers that indicate content should be preserved during merge\n */\nconst PRESERVE_MARKERS = [\n '# local',\n '# LOCAL',\n '# machine-specific',\n '# MACHINE-SPECIFIC',\n '# machine specific',\n '# do not sync',\n '# DO NOT SYNC',\n '# keep',\n '# KEEP',\n '# private',\n '# PRIVATE',\n '# tuck:preserve',\n '# tuck:keep',\n '# tuck:local',\n];\n\n/**\n * Shell file patterns that are known to be shell configuration\n */\nconst SHELL_FILE_PATTERNS = [\n '.zshrc',\n '.bashrc',\n '.bash_profile',\n '.profile',\n '.zprofile',\n '.zshenv',\n '.bash_aliases',\n '.aliases',\n '.functions',\n];\n\nexport interface MergeBlock {\n type: 'preserved' | 'incoming' | 'local';\n content: string;\n marker?: string;\n lineStart: number;\n lineEnd: number;\n}\n\nexport interface MergeResult {\n content: string;\n preservedBlocks: number;\n incomingBlocks: number;\n conflicts: MergeConflict[];\n}\n\nexport interface MergeConflict {\n type: 'duplicate_export' | 'duplicate_alias' | 'duplicate_function';\n name: string;\n localLine: number;\n incomingLine: number;\n}\n\nexport interface ParsedExport {\n name: string;\n value: string;\n line: number;\n fullLine: string;\n}\n\nexport interface ParsedAlias {\n name: string;\n value: string;\n line: number;\n fullLine: string;\n}\n\nexport interface ParsedFunction {\n name: string;\n content: string;\n lineStart: number;\n lineEnd: number;\n}\n\n/**\n * Check if a file is a shell configuration file\n */\nexport const isShellFile = (filePath: string): boolean => {\n const fileName = filePath.split('/').pop() || '';\n return SHELL_FILE_PATTERNS.some(\n (pattern) => fileName === pattern || fileName.endsWith(pattern)\n );\n};\n\n/**\n * Parse export statements from shell content\n * Handles: export FOO=bar, export FOO=\"bar\", FOO=bar\n */\nexport const parseExports = (content: string): ParsedExport[] => {\n const exports: ParsedExport[] = [];\n const lines = content.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n // Skip comments and empty lines\n if (line.startsWith('#') || !line) continue;\n\n // Match export statements\n const exportMatch = line.match(/^(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);\n if (exportMatch) {\n exports.push({\n name: exportMatch[1],\n value: exportMatch[2],\n line: i + 1,\n fullLine: lines[i],\n });\n }\n }\n\n return exports;\n};\n\n/**\n * Parse alias definitions from shell content\n * Handles: alias foo='bar', alias foo=\"bar\"\n */\nexport const parseAliases = (content: string): ParsedAlias[] => {\n const aliases: ParsedAlias[] = [];\n const lines = content.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n // Skip comments and empty lines\n if (line.startsWith('#') || !line) continue;\n\n // Match alias statements\n const aliasMatch = line.match(/^alias\\s+([a-zA-Z_][a-zA-Z0-9_-]*)=(['\"]?)(.+?)\\2\\s*$/);\n if (aliasMatch) {\n aliases.push({\n name: aliasMatch[1],\n value: aliasMatch[3],\n line: i + 1,\n fullLine: lines[i],\n });\n }\n }\n\n return aliases;\n};\n\n/**\n * Find blocks that should be preserved during merge\n * A preserved block starts with a preserve marker and ends at:\n * - The next non-indented non-comment line\n * - The end of file\n * - Another preserve marker\n */\nexport const findPreservedBlocks = (content: string): MergeBlock[] => {\n const blocks: MergeBlock[] = [];\n const lines = content.split('\\n');\n let currentBlock: MergeBlock | null = null;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmedLine = line.trim();\n\n // Check if this line has a preserve marker\n const marker = PRESERVE_MARKERS.find((m) => trimmedLine.includes(m));\n\n if (marker) {\n // Save previous block if exists\n if (currentBlock) {\n currentBlock.lineEnd = i;\n currentBlock.content = lines.slice(currentBlock.lineStart - 1, i).join('\\n');\n blocks.push(currentBlock);\n }\n\n // Start new preserved block\n currentBlock = {\n type: 'preserved',\n content: '',\n marker,\n lineStart: i + 1,\n lineEnd: i + 1,\n };\n } else if (currentBlock) {\n // Check if we should end the current block\n // End if: empty line followed by non-indented content, or end of file\n const isEndOfBlock =\n (trimmedLine === '' && i + 1 < lines.length && !lines[i + 1].startsWith(' ') && !lines[i + 1].startsWith('\\t') && lines[i + 1].trim() !== '' && !lines[i + 1].trim().startsWith('#')) ||\n i === lines.length - 1;\n\n if (isEndOfBlock) {\n currentBlock.lineEnd = i + 1;\n currentBlock.content = lines.slice(currentBlock.lineStart - 1, i + 1).join('\\n');\n blocks.push(currentBlock);\n currentBlock = null;\n }\n }\n }\n\n // Handle block that extends to end of file\n if (currentBlock) {\n currentBlock.lineEnd = lines.length;\n currentBlock.content = lines.slice(currentBlock.lineStart - 1).join('\\n');\n blocks.push(currentBlock);\n }\n\n return blocks;\n};\n\n/**\n * Extract PATH modifications from content\n */\nexport const extractPathModifications = (content: string): string[] => {\n const paths: string[] = [];\n const lines = content.split('\\n');\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.startsWith('#')) continue;\n\n // Match PATH exports\n if (trimmed.includes('PATH') && (trimmed.includes('export') || trimmed.includes('='))) {\n paths.push(line);\n }\n }\n\n return paths;\n};\n\n/**\n * Smart merge of shell configuration files\n * Preserves local customizations while applying incoming changes\n */\nexport const smartMerge = async (\n localPath: string,\n incomingContent: string\n): Promise<MergeResult> => {\n const expandedPath = expandPath(localPath);\n\n // If local file doesn't exist, just return incoming content\n if (!(await pathExists(expandedPath))) {\n return {\n content: incomingContent,\n preservedBlocks: 0,\n incomingBlocks: 1,\n conflicts: [],\n };\n }\n\n const localContent = await readFile(expandedPath, 'utf-8');\n\n // Find blocks to preserve from local content\n const preservedBlocks = findPreservedBlocks(localContent);\n\n // Parse exports and aliases from both files\n const localExports = parseExports(localContent);\n const incomingExports = parseExports(incomingContent);\n const localAliases = parseAliases(localContent);\n const incomingAliases = parseAliases(incomingContent);\n\n // Find conflicts\n const conflicts: MergeConflict[] = [];\n\n // Check for duplicate exports\n for (const local of localExports) {\n const duplicate = incomingExports.find((e) => e.name === local.name);\n if (duplicate && local.value !== duplicate.value) {\n conflicts.push({\n type: 'duplicate_export',\n name: local.name,\n localLine: local.line,\n incomingLine: duplicate.line,\n });\n }\n }\n\n // Check for duplicate aliases\n for (const local of localAliases) {\n const duplicate = incomingAliases.find((a) => a.name === local.name);\n if (duplicate && local.value !== duplicate.value) {\n conflicts.push({\n type: 'duplicate_alias',\n name: local.name,\n localLine: local.line,\n incomingLine: duplicate.line,\n });\n }\n }\n\n // Build merged content\n let mergedContent = incomingContent;\n\n // Append preserved blocks at the end\n if (preservedBlocks.length > 0) {\n mergedContent += '\\n\\n';\n mergedContent += '# ============================================\\n';\n mergedContent += '# LOCAL CUSTOMIZATIONS (preserved by tuck)\\n';\n mergedContent += '# ============================================\\n\\n';\n\n for (const block of preservedBlocks) {\n mergedContent += block.content + '\\n\\n';\n }\n }\n\n return {\n content: mergedContent.trim() + '\\n',\n preservedBlocks: preservedBlocks.length,\n incomingBlocks: 1,\n conflicts,\n };\n};\n\n/**\n * Generate a diff-like preview of what will change\n */\nexport const generateMergePreview = async (\n localPath: string,\n incomingContent: string\n): Promise<string> => {\n const expandedPath = expandPath(localPath);\n\n if (!(await pathExists(expandedPath))) {\n return `New file will be created:\\n${incomingContent.slice(0, 500)}${incomingContent.length > 500 ? '...' : ''}`;\n }\n\n const localContent = await readFile(expandedPath, 'utf-8');\n const preservedBlocks = findPreservedBlocks(localContent);\n const localExports = parseExports(localContent);\n const incomingExports = parseExports(incomingContent);\n\n const lines: string[] = [];\n\n lines.push('=== Merge Preview ===');\n lines.push('');\n\n // Show preserved blocks\n if (preservedBlocks.length > 0) {\n lines.push(`📌 ${preservedBlocks.length} block(s) will be preserved:`);\n for (const block of preservedBlocks) {\n lines.push(` - Lines ${block.lineStart}-${block.lineEnd} (${block.marker})`);\n }\n lines.push('');\n }\n\n // Show export changes\n const newExports = incomingExports.filter(\n (e) => !localExports.find((l) => l.name === e.name)\n );\n const changedExports = incomingExports.filter((e) => {\n const local = localExports.find((l) => l.name === e.name);\n return local && local.value !== e.value;\n });\n\n if (newExports.length > 0) {\n lines.push(`➕ ${newExports.length} new export(s):`);\n for (const exp of newExports.slice(0, 5)) {\n lines.push(` + ${exp.name}=${exp.value.slice(0, 50)}`);\n }\n if (newExports.length > 5) {\n lines.push(` ... and ${newExports.length - 5} more`);\n }\n lines.push('');\n }\n\n if (changedExports.length > 0) {\n lines.push(`🔄 ${changedExports.length} export(s) will be updated:`);\n for (const exp of changedExports.slice(0, 5)) {\n const local = localExports.find((l) => l.name === exp.name);\n lines.push(` ~ ${exp.name}: \"${local?.value.slice(0, 20)}...\" → \"${exp.value.slice(0, 20)}...\"`);\n }\n if (changedExports.length > 5) {\n lines.push(` ... and ${changedExports.length - 5} more`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n};\n\n/**\n * Check if content has any preserve markers\n */\nexport const hasPreserveMarkers = (content: string): boolean => {\n return PRESERVE_MARKERS.some((marker) => content.includes(marker));\n};\n\n/**\n * Add a preserve marker to content\n */\nexport const addPreserveMarker = (content: string, marker = '# tuck:preserve'): string => {\n return `${marker}\\n${content}`;\n};\n","import { Command } from 'commander';\nimport { prompts, logger, colors as c } from '../ui/index.js';\nimport { collapsePath } from '../lib/paths.js';\nimport {\n listSnapshots,\n getSnapshot,\n getLatestSnapshot,\n restoreSnapshot,\n restoreFileFromSnapshot,\n deleteSnapshot,\n getSnapshotsSize,\n formatSnapshotSize,\n formatSnapshotDate,\n Snapshot,\n} from '../lib/timemachine.js';\n\nexport interface UndoOptions {\n list?: boolean;\n latest?: boolean;\n file?: string;\n delete?: string;\n force?: boolean;\n dryRun?: boolean;\n}\n\n/**\n * Display a list of available snapshots\n */\nconst showSnapshotList = async (): Promise<void> => {\n const snapshots = await listSnapshots();\n\n if (snapshots.length === 0) {\n logger.warning('No backup snapshots found');\n logger.dim('Snapshots are created automatically when using `tuck apply`');\n return;\n }\n\n logger.heading('Backup Snapshots:');\n logger.blank();\n\n for (const snapshot of snapshots) {\n const date = formatSnapshotDate(snapshot.id);\n const fileCount = snapshot.files.filter((f) => f.existed).length;\n\n console.log(c.cyan(` ${snapshot.id}`));\n console.log(c.dim(` Date: ${date}`));\n console.log(c.dim(` Reason: ${snapshot.reason}`));\n console.log(c.dim(` Files: ${fileCount} file(s) backed up`));\n console.log(c.dim(` Machine: ${snapshot.machine}`));\n console.log();\n }\n\n const totalSize = await getSnapshotsSize();\n logger.dim(`Total backup size: ${formatSnapshotSize(totalSize)}`);\n logger.blank();\n logger.info('To restore a snapshot: tuck undo <snapshot-id>');\n logger.info('To restore the latest: tuck undo --latest');\n};\n\n/**\n * Display details of a specific snapshot\n */\nconst showSnapshotDetails = (snapshot: Snapshot): void => {\n console.log();\n console.log(c.bold('Snapshot Details:'));\n console.log(c.dim(` ID: ${snapshot.id}`));\n console.log(c.dim(` Date: ${formatSnapshotDate(snapshot.id)}`));\n console.log(c.dim(` Reason: ${snapshot.reason}`));\n console.log(c.dim(` Machine: ${snapshot.machine}`));\n console.log();\n console.log(c.bold('Files in snapshot:'));\n\n for (const file of snapshot.files) {\n if (file.existed) {\n console.log(c.dim(` ok ${collapsePath(file.originalPath)}`));\n } else {\n console.log(c.dim(` - ${collapsePath(file.originalPath)} (did not exist)`));\n }\n }\n console.log();\n};\n\n/**\n * Restore from a specific snapshot\n */\nconst restoreFromSnapshot = async (snapshotId: string, options: UndoOptions): Promise<void> => {\n const snapshot = await getSnapshot(snapshotId);\n\n if (!snapshot) {\n logger.error(`Snapshot not found: ${snapshotId}`);\n const snapshots = await listSnapshots();\n if (snapshots.length > 0) {\n logger.info('Available snapshots:');\n for (const s of snapshots.slice(0, 5)) {\n logger.dim(` ${s.id} - ${formatSnapshotDate(s.id)}`);\n }\n if (snapshots.length > 5) {\n logger.dim(` ... and ${snapshots.length - 5} more`);\n }\n }\n return;\n }\n\n // Show snapshot details\n showSnapshotDetails(snapshot);\n\n // Confirm unless --force or dry-run\n if (!options.force && !options.dryRun) {\n const backedUpCount = snapshot.files.filter((f) => f.existed).length;\n const confirmed = await prompts.confirm(\n `Restore ${backedUpCount} file(s) from this snapshot?`,\n true\n );\n\n if (!confirmed) {\n logger.info('Restore cancelled');\n return;\n }\n }\n\n // Dry run\n if (options.dryRun) {\n logger.heading('Dry run - would restore:');\n for (const file of snapshot.files) {\n if (file.existed) {\n logger.file('modify', collapsePath(file.originalPath));\n } else {\n logger.file('delete', `${collapsePath(file.originalPath)} (would remove)`);\n }\n }\n return;\n }\n\n // Restore\n logger.info('Restoring files...');\n const restoredFiles = await restoreSnapshot(snapshotId);\n\n logger.blank();\n logger.success(`Restored ${restoredFiles.length} file(s)`);\n\n for (const file of restoredFiles) {\n logger.dim(` ok ${collapsePath(file)}`);\n }\n};\n\n/**\n * Restore a single file from a snapshot\n */\nconst restoreSingleFile = async (\n snapshotId: string,\n filePath: string,\n options: UndoOptions\n): Promise<void> => {\n const snapshot = await getSnapshot(snapshotId);\n\n if (!snapshot) {\n logger.error(`Snapshot not found: ${snapshotId}`);\n return;\n }\n\n // Dry run\n if (options.dryRun) {\n logger.info(`Would restore ${filePath} from snapshot ${snapshotId}`);\n return;\n }\n\n // Restore the file\n await restoreFileFromSnapshot(snapshotId, filePath);\n logger.success(`Restored ${filePath}`);\n};\n\n/**\n * Delete a snapshot\n */\nconst removeSnapshot = async (snapshotId: string, options: UndoOptions): Promise<void> => {\n const snapshot = await getSnapshot(snapshotId);\n\n if (!snapshot) {\n logger.error(`Snapshot not found: ${snapshotId}`);\n return;\n }\n\n // Confirm unless --force\n if (!options.force) {\n showSnapshotDetails(snapshot);\n const confirmed = await prompts.confirm('Delete this snapshot permanently?', false);\n\n if (!confirmed) {\n logger.info('Deletion cancelled');\n return;\n }\n }\n\n await deleteSnapshot(snapshotId);\n logger.success(`Deleted snapshot: ${snapshotId}`);\n};\n\n/**\n * Interactive undo selection\n */\nconst runInteractiveUndo = async (): Promise<void> => {\n prompts.intro('tuck undo');\n\n const snapshots = await listSnapshots();\n\n if (snapshots.length === 0) {\n prompts.log.warning('No backup snapshots available');\n prompts.note('Snapshots are created when using `tuck apply`', 'Info');\n return;\n }\n\n // Let user select a snapshot\n const snapshotOptions = snapshots.map((s) => ({\n value: s.id,\n label: `${s.id} - ${s.reason.slice(0, 40)}${s.reason.length > 40 ? '...' : ''}`,\n hint: `${s.files.filter((f) => f.existed).length} files`,\n }));\n\n const selectedId = await prompts.select('Select a snapshot to restore:', snapshotOptions);\n\n const snapshot = await getSnapshot(selectedId);\n if (!snapshot) {\n prompts.log.error('Snapshot not found');\n return;\n }\n\n // Show what will be restored\n console.log();\n prompts.log.info('Files in this snapshot:');\n for (const file of snapshot.files.slice(0, 10)) {\n if (file.existed) {\n console.log(c.dim(` ${collapsePath(file.originalPath)}`));\n }\n }\n if (snapshot.files.length > 10) {\n console.log(c.dim(` ... and ${snapshot.files.length - 10} more`));\n }\n console.log();\n\n // Confirm\n const confirmed = await prompts.confirm('Restore these files?', true);\n\n if (!confirmed) {\n prompts.cancel('Restore cancelled');\n return;\n }\n\n // Restore\n const spinner = prompts.spinner();\n spinner.start('Restoring files...');\n\n const restoredFiles = await restoreSnapshot(selectedId);\n\n spinner.stop(`Restored ${restoredFiles.length} files`);\n\n prompts.outro('Done!');\n};\n\n/**\n * Main undo command handler\n */\nconst runUndo = async (snapshotId: string | undefined, options: UndoOptions): Promise<void> => {\n // Handle --list\n if (options.list) {\n await showSnapshotList();\n return;\n }\n\n // Handle --delete\n if (options.delete) {\n await removeSnapshot(options.delete, options);\n return;\n }\n\n // Handle --latest\n if (options.latest) {\n const latest = await getLatestSnapshot();\n if (!latest) {\n logger.warning('No backup snapshots available');\n return;\n }\n await restoreFromSnapshot(latest.id, options);\n return;\n }\n\n // Handle specific snapshot ID\n if (snapshotId) {\n // Check if we're restoring a single file\n if (options.file) {\n await restoreSingleFile(snapshotId, options.file, options);\n } else {\n await restoreFromSnapshot(snapshotId, options);\n }\n return;\n }\n\n // No arguments - run interactive mode\n await runInteractiveUndo();\n};\n\nexport const undoCommand = new Command('undo')\n .description('Restore files from a Time Machine backup snapshot')\n .argument('[snapshot-id]', 'Snapshot ID to restore (format: YYYY-MM-DD-HHMMSS)')\n .option('-l, --list', 'List all available backup snapshots')\n .option('--latest', 'Restore the most recent snapshot')\n .option('--file <path>', 'Restore a single file from the snapshot')\n .option('--delete <id>', 'Delete a specific snapshot')\n .option('-f, --force', 'Skip confirmation prompts')\n .option('--dry-run', 'Show what would be restored without making changes')\n .action(async (snapshotId: string | undefined, options: UndoOptions) => {\n await runUndo(snapshotId, options);\n });\n","import { Command } from 'commander';\nimport { prompts, logger, banner, colors as c } from '../ui/index.js';\nimport { getTuckDir, collapsePath, expandPath } from '../lib/paths.js';\nimport { loadManifest, getTrackedFileBySource } from '../lib/manifest.js';\nimport { detectDotfiles, DETECTION_CATEGORIES, DetectedFile } from '../lib/detect.js';\nimport { NotInitializedError } from '../errors.js';\nimport { trackFilesWithProgress, type FileToTrack } from '../lib/fileTracking.js';\nimport { shouldExcludeFromBin } from '../lib/binary.js';\nimport { isIgnored } from '../lib/tuckignore.js';\n\nexport interface ScanOptions {\n all?: boolean;\n category?: string;\n json?: boolean;\n quick?: boolean;\n}\n\ninterface SelectableFile extends DetectedFile {\n selected: boolean;\n alreadyTracked: boolean;\n}\n\n/**\n * Group selectable files by category\n */\nconst groupSelectableByCategory = (files: SelectableFile[]): Record<string, SelectableFile[]> => {\n const grouped: Record<string, SelectableFile[]> = {};\n\n for (const file of files) {\n if (!grouped[file.category]) {\n grouped[file.category] = [];\n }\n grouped[file.category].push(file);\n }\n\n return grouped;\n};\n\n/**\n * Display detected files grouped by category\n */\nconst displayGroupedFiles = (files: SelectableFile[], showAll: boolean): void => {\n const grouped = groupSelectableByCategory(files);\n const categories = Object.keys(grouped).sort((a, b) => {\n // Sort by category order in DETECTION_CATEGORIES\n const order = Object.keys(DETECTION_CATEGORIES);\n return order.indexOf(a) - order.indexOf(b);\n });\n\n for (const category of categories) {\n const categoryFiles = grouped[category];\n const config = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n const newFiles = categoryFiles.filter((f) => !f.alreadyTracked);\n const trackedFiles = categoryFiles.filter((f) => f.alreadyTracked);\n\n console.log();\n console.log(\n c.bold(`${config.icon} ${config.name}`) +\n c.dim(` (${newFiles.length} new, ${trackedFiles.length} tracked)`)\n );\n console.log(c.dim('─'.repeat(50)));\n\n for (const file of categoryFiles) {\n if (!showAll && file.alreadyTracked) continue;\n\n const status = file.selected ? c.green('[x]') : c.dim('[ ]');\n const name = file.path;\n const tracked = file.alreadyTracked ? c.dim(' (tracked)') : '';\n const sensitive = file.sensitive ? c.yellow(' [!]') : '';\n const dir = file.isDirectory ? c.cyan(' [dir]') : '';\n\n console.log(` ${status} ${name}${dir}${sensitive}${tracked}`);\n console.log(c.dim(` ${file.description}`));\n }\n }\n};\n\n/**\n * Interactive file selection\n */\nconst runInteractiveSelection = async (files: SelectableFile[]): Promise<SelectableFile[]> => {\n const newFiles = files.filter((f) => !f.alreadyTracked);\n\n if (newFiles.length === 0) {\n prompts.log.success('All detected dotfiles are already being tracked!');\n return [];\n }\n\n // Group files for selection\n const grouped = groupSelectableByCategory(newFiles);\n const selectedFiles: SelectableFile[] = [];\n\n // Ask for each category\n for (const [category, categoryFiles] of Object.entries(grouped)) {\n const config = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n\n console.log();\n console.log(c.bold(`${config.icon} ${config.name}`));\n console.log(c.dim(config.description || ''));\n console.log();\n\n // Create options for multiselect\n const options = categoryFiles.map((file: SelectableFile) => {\n let label = file.path;\n if (file.sensitive) {\n label += c.yellow(' [!]');\n }\n if (file.isDirectory) {\n label += c.cyan(' [dir]');\n }\n\n return {\n value: file.path,\n label,\n hint: file.description,\n };\n });\n\n // Pre-select all non-sensitive files by default\n const nonSensitiveFiles = categoryFiles.filter((f) => !f.sensitive);\n const initialValues = nonSensitiveFiles.map((f) => f.path);\n\n const selected = await prompts.multiselect(\n `Select files to track from ${config.name}:`,\n options,\n { initialValues }\n );\n\n // Mark selected files\n for (const file of categoryFiles) {\n if (selected.includes(file.path)) {\n file.selected = true;\n selectedFiles.push(file);\n }\n }\n }\n\n return selectedFiles;\n};\n\n/**\n * Quick display mode - just show what's detected\n */\nconst runQuickScan = async (files: SelectableFile[]): Promise<void> => {\n const newFiles = files.filter((f) => !f.alreadyTracked);\n const trackedFiles = files.filter((f) => f.alreadyTracked);\n\n console.log();\n console.log(\n c.bold.cyan('Detected Dotfiles: ') +\n c.white(`${newFiles.length} new, ${trackedFiles.length} already tracked`)\n );\n\n displayGroupedFiles(files, false);\n\n console.log();\n console.log(c.dim('─'.repeat(60)));\n console.log();\n\n if (newFiles.length > 0) {\n logger.info(`Found ${newFiles.length} new dotfiles to track`);\n logger.dim('Run `tuck scan` (without --quick) to interactively select files');\n logger.dim('Or run `tuck add <path>` to add specific files');\n } else {\n logger.success('All detected dotfiles are already being tracked!');\n }\n};\n\n/**\n * Summary display after selection\n */\nconst showSummary = (selected: SelectableFile[]): void => {\n if (selected.length === 0) {\n logger.info('No files selected');\n return;\n }\n\n console.log();\n console.log(c.bold.cyan(`Selected ${selected.length} files to track:`));\n console.log(c.dim('─'.repeat(50)));\n console.log();\n\n const grouped = groupSelectableByCategory(selected);\n\n for (const [category, files] of Object.entries(grouped)) {\n const config = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n console.log(c.bold(`${config.icon} ${config.name}`));\n\n for (const file of files) {\n const sensitive = file.sensitive ? c.yellow(' ⚠') : '';\n console.log(c.dim(` • ${collapsePath(file.path)}${sensitive}`));\n }\n console.log();\n }\n\n // Show warnings for sensitive files\n const sensitiveFiles = selected.filter((f) => f.sensitive);\n if (sensitiveFiles.length > 0) {\n console.log(c.yellow('⚠ Warning: Some files may contain sensitive data'));\n console.log(c.dim(' Make sure your repository is private!'));\n console.log();\n }\n};\n\n/**\n * Add selected files with beautiful progress display\n */\nconst addFilesWithProgress = async (\n selected: SelectableFile[],\n tuckDir: string\n): Promise<number> => {\n // Convert SelectableFile to FileToTrack\n const filesToTrack: FileToTrack[] = selected.map((f) => ({\n path: f.path,\n category: f.category,\n }));\n\n // Use the shared tracking utility\n const result = await trackFilesWithProgress(filesToTrack, tuckDir, {\n showCategory: true,\n actionVerb: 'Tracking',\n });\n\n return result.succeeded;\n};\n\n/**\n * Main scan function\n */\nconst runScan = async (options: ScanOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Check if tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Detect dotfiles\n const spinner = prompts.spinner();\n spinner.start('Scanning for dotfiles...');\n\n const detected = await detectDotfiles();\n\n spinner.stop(`Found ${detected.length} dotfiles on this system`);\n\n if (detected.length === 0) {\n logger.warning('No common dotfiles detected on this system');\n return;\n }\n\n // Check which files are already tracked\n const selectableFiles: SelectableFile[] = [];\n\n for (const file of detected) {\n const tracked = await getTrackedFileBySource(tuckDir, file.path);\n\n // Skip if in .tuckignore\n if (await isIgnored(tuckDir, file.path)) {\n continue;\n }\n\n // Skip if binary executable in bin directory\n if (await shouldExcludeFromBin(expandPath(file.path))) {\n continue;\n }\n\n selectableFiles.push({\n ...file,\n selected: true, // All selected by default\n alreadyTracked: tracked !== null,\n });\n }\n\n // Filter by category if specified\n let filesToShow = selectableFiles;\n if (options.category) {\n filesToShow = selectableFiles.filter((f) => f.category === options.category);\n if (filesToShow.length === 0) {\n logger.warning(`No dotfiles found in category: ${options.category}`);\n logger.info('Available categories:');\n for (const [key, config] of Object.entries(DETECTION_CATEGORIES)) {\n console.log(c.dim(` ${config.icon} ${key} - ${config.name}`));\n }\n return;\n }\n }\n\n // JSON output\n if (options.json) {\n console.log(JSON.stringify(filesToShow, null, 2));\n return;\n }\n\n // Quick mode - just display\n if (options.quick) {\n await runQuickScan(filesToShow);\n return;\n }\n\n // Interactive mode\n banner();\n prompts.intro('tuck scan');\n\n const newFiles = filesToShow.filter((f) => !f.alreadyTracked);\n const trackedCount = filesToShow.filter((f) => f.alreadyTracked).length;\n\n prompts.log.info(\n `Found ${filesToShow.length} dotfiles (${newFiles.length} new, ${trackedCount} tracked)`\n );\n\n if (newFiles.length === 0) {\n prompts.log.success('All detected dotfiles are already being tracked!');\n prompts.outro('Nothing to do');\n return;\n }\n\n // Ask how to proceed\n const action = await prompts.select('How would you like to proceed?', [\n {\n value: 'all',\n label: 'Track all new files',\n hint: `Add all ${newFiles.length} files`,\n },\n {\n value: 'select',\n label: 'Select files to track',\n hint: 'Choose which files to add',\n },\n {\n value: 'preview',\n label: 'Just show me what was found',\n hint: 'Display files without tracking',\n },\n ]);\n\n if (action === 'preview') {\n displayGroupedFiles(filesToShow, options.all || false);\n prompts.outro('Run `tuck scan` again to select files');\n return;\n }\n\n let selected: SelectableFile[];\n\n if (action === 'all') {\n selected = newFiles.map((f) => ({ ...f, selected: true }));\n } else {\n selected = await runInteractiveSelection(filesToShow);\n }\n\n if (selected.length === 0) {\n prompts.cancel('No files selected');\n return;\n }\n\n // Show summary of what will be tracked\n showSummary(selected);\n\n const confirmed = await prompts.confirm(`Track these ${selected.length} files?`, true);\n\n if (!confirmed) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n // Add the files with beautiful progress display\n const addedCount = await addFilesWithProgress(selected, tuckDir);\n\n if (addedCount > 0) {\n // Ask if user wants to sync now\n console.log();\n const shouldSync = await prompts.confirm('Would you like to sync these changes now?', true);\n\n if (shouldSync) {\n console.log();\n const { runSync } = await import('./sync.js');\n await runSync({});\n } else {\n prompts.outro(\"Run 'tuck sync' when you're ready to commit changes\");\n }\n } else {\n prompts.outro('No files were added');\n }\n};\n\nexport const scanCommand = new Command('scan')\n .description('Scan system for dotfiles and select which to track')\n .option('-a, --all', 'Show all files including already tracked ones')\n .option('-c, --category <name>', 'Filter by category (shell, git, editors, etc.)')\n .option('-q, --quick', 'Quick scan - just show detected files without interactive selection')\n .option('--json', 'Output results as JSON')\n .action(async (options: ScanOptions) => {\n await runScan(options);\n });\n"],"mappings":"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","names":["logSymbols","figures","indent","p","logSymbols","spinner","text","p","logSymbols","figures","figures","homedir","join","dirname","z","chalk","z","fileStrategySchema","readFile","writeFile","fetch","join","execFile","promisify","execFileAsync","log","homedir","join","readFile","pathExists","platform","writeFile","dirname","spawn","resolve","unlink","password","join","basename","isAbsolute","stat","isDirectory","readFile","stat","readdir","join","dirname","basename","constants","content","chalk","ensureDir","dirname","spinner","resolve","join","copy","ensureDir","pathExists","promisify","chalk","join","stat","confirm","join","readFile","writeFile","p","readFile","stat","p","readFile","writeFile","chmod","stat","join","ensureDir","readFile","writeFile","unlink","stat","dirname","basename","join","execFile","promisify","z","execFileAsync","p","p","Command","init_secrets","spinner","simpleGit","scanContent","p","Command","join","init_secrets","fetch","c","spinner","Command","chalk","Command","join","writeFile","ensureDir","copy","readFile","rm","execFile","promisify","execFileAsync","spinner","readdir","p","getPreferredRemoteProtocol","DETECTION_CATEGORIES","hostname","removeRemote","stat","runRestore","Command","basename","stat","basename","dirname","PRIVATE_KEY_PATTERNS","SENSITIVE_FILE_PATTERNS","basename","isSensitiveFile","sizeCheck","scanAndHandleSecrets","confirm","scanAndHandleSecrets","runSync","Command","Command","join","validateAndPrepareFiles","confirm","Command","remoteUrl","confirm","Command","fetch","Command","boxen","logSymbols","figures","Command","groupByCategory","group","Command","join","readFile","join","repoExists","systemChecksum","repoChecksum","Command","Command","resolve","confirm","colors","currentValue","Command","join","readFile","rm","chmod","stat","ensureDir","tmpdir","join","dirname","readdir","readFile","writeFile","rm","stat","copy","ensureDir","pathExists","homedir","pathExists","readdir","join","stat","readFile","readFile","stat","chmod","join","tmpdir","ensureDir","readFile","writeFile","dirname","spinner","rm","Command","Command","spinner","Command","Command","spinner","runSync","Command","init_secrets","Command","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../src/ui/theme.ts","../src/ui/banner.ts","../src/ui/logger.ts","../src/ui/prompts.ts","../src/ui/spinner.ts","../src/ui/table.ts","../src/ui/progress.ts","../src/ui/index.ts","../src/constants.ts","../src/lib/paths.ts","../src/schemas/secrets.schema.ts","../src/schemas/config.schema.ts","../src/errors.ts","../src/lib/config.ts","../src/schemas/manifest.schema.ts","../src/lib/manifest.ts","../src/lib/git.ts","../src/lib/providers/types.ts","../src/lib/validation.ts","../src/lib/providers/gitlab.ts","../src/lib/github.ts","../src/lib/detect.ts","../src/lib/files.ts","../src/lib/fileTracking.ts","../src/lib/backup.ts","../src/lib/hooks.ts","../src/commands/restore.ts","../src/lib/tuckignore.ts","../src/lib/secrets/patterns.ts","../src/lib/secrets/scanner.ts","../src/lib/secrets/store.ts","../src/lib/secrets/redactor.ts","../src/lib/secrets/external.ts","../src/lib/secrets/index.ts","../src/commands/secrets.ts","../src/commands/sync.ts","../src/index.ts","../src/commands/init.ts","../src/lib/providerSetup.ts","../src/lib/providers/index.ts","../src/lib/providers/github.ts","../src/lib/providers/local.ts","../src/lib/providers/custom.ts","../src/commands/add.ts","../src/lib/binary.ts","../src/commands/remove.ts","../src/commands/index.ts","../src/commands/push.ts","../src/lib/remoteChecks.ts","../src/commands/pull.ts","../src/commands/status.ts","../src/commands/list.ts","../src/commands/diff.ts","../src/commands/config.ts","../src/commands/apply.ts","../src/lib/timemachine.ts","../src/lib/merge.ts","../src/commands/undo.ts","../src/commands/scan.ts","../src/lib/updater.ts"],"sourcesContent":["/**\n * Design System for tuck CLI\n * Centralized design tokens, colors, icons, and helpers\n */\n\nimport chalk from 'chalk';\nimport figures from 'figures';\nimport logSymbols from 'log-symbols';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Layout Constants\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const TERMINAL_WIDTH = 100;\nexport const CONTENT_WIDTH = 80;\nexport const DIVIDER_WIDTH = 60;\nexport const INDENT = ' ';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Colors (semantic naming)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const colors = {\n // Brand\n brand: chalk.cyan,\n brandBold: chalk.bold.cyan,\n brandDim: chalk.dim.cyan,\n brandBg: chalk.bgCyan.black,\n\n // Status\n success: chalk.green,\n warning: chalk.yellow,\n error: chalk.red,\n info: chalk.blue,\n\n // Text\n muted: chalk.dim,\n bold: chalk.bold,\n highlight: chalk.bold.white,\n\n // Direct color aliases (for compatibility)\n cyan: chalk.cyan,\n green: chalk.green,\n yellow: chalk.yellow,\n red: chalk.red,\n blue: chalk.blue,\n dim: chalk.dim,\n white: chalk.white,\n};\n\n// Shorthand alias\nexport const c = colors;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Icons (with automatic Unicode fallbacks via figures)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const icons = {\n // Status icons (colored, from log-symbols)\n success: logSymbols.success,\n error: logSymbols.error,\n warning: logSymbols.warning,\n info: logSymbols.info,\n\n // Action icons (from figures - auto fallback)\n tick: figures.tick,\n cross: figures.cross,\n pointer: figures.pointer,\n arrowRight: figures.arrowRight,\n arrowDown: figures.arrowDown,\n arrowUp: figures.arrowUp,\n\n // Progress icons\n circle: figures.circle,\n circleFilled: figures.circleFilled,\n bullet: figures.bullet,\n ellipsis: figures.ellipsis,\n\n // File operations\n add: c.success(figures.tick),\n remove: c.error(figures.cross),\n modify: c.warning('~'),\n sync: c.brand(figures.arrowRight),\n\n // Tree/structure\n line: figures.line,\n corner: figures.lineDownRight,\n tee: figures.lineDownRightArc,\n\n // Category icons\n shell: '$',\n git: figures.star,\n editors: figures.pointer,\n terminal: '#',\n ssh: figures.warning,\n misc: figures.bullet,\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Category Configuration (icons + colors)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CategoryStyle {\n icon: string;\n color: typeof chalk;\n}\n\nexport const categoryStyles: Record<string, CategoryStyle> = {\n shell: { icon: '$', color: c.success },\n git: { icon: figures.star, color: c.warning },\n editors: { icon: figures.pointer, color: c.brand },\n terminal: { icon: '#', color: c.info },\n ssh: { icon: figures.warning, color: c.error },\n misc: { icon: figures.bullet, color: c.muted },\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Layout Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Create a horizontal divider line */\nexport const divider = (width = DIVIDER_WIDTH): string => c.muted('─'.repeat(width));\n\n/** Create indentation */\nexport const indent = (level = 1): string => INDENT.repeat(level);\n\n/** Print a blank line */\nexport const spacer = (): void => {\n console.log();\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Text Formatting Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Format a file path with brand color */\nexport const formatPath = (path: string): string => c.brand(path);\n\n/** Format a count with proper pluralization: \"3 files\" */\nexport const formatCount = (n: number, singular: string, plural?: string): string => {\n const word = n === 1 ? singular : plural || `${singular}s`;\n return `${c.bold(n.toString())} ${word}`;\n};\n\n/** Format a category with its icon */\nexport const formatCategory = (category: string): string => {\n const style = categoryStyles[category] || categoryStyles.misc;\n return `${style.color(style.icon)} ${category}`;\n};\n\n/** Format a status string with appropriate color */\nexport const formatStatus = (status: string): string => {\n switch (status) {\n case 'added':\n return c.success(status);\n case 'modified':\n return c.warning(status);\n case 'deleted':\n return c.error(status);\n default:\n return c.muted(status);\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Message Helpers (concise, consistent)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Format a hint message (dimmed, for secondary info) */\nexport const hint = (message: string): string => c.muted(message);\n\n/** Format a command suggestion */\nexport const cmd = (command: string): string => c.brand(`'${command}'`);\n\n/** Print a section header */\nexport const sectionHeader = (title: string): void => {\n console.log();\n console.log(c.brandBold(title));\n console.log(divider());\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Progress Display Modes\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type ProgressMode = 'detailed' | 'compact' | 'minimal';\n\n/** Determine the best progress display mode based on item count */\nexport const getProgressMode = (itemCount: number): ProgressMode => {\n if (itemCount <= 20) return 'detailed';\n if (itemCount <= 100) return 'compact';\n return 'minimal';\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Box Styles (for boxen)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const boxStyles = {\n /** Compact header box */\n header: {\n padding: { top: 0, bottom: 0, left: 1, right: 1 },\n borderStyle: 'round' as const,\n borderColor: 'cyan' as const,\n },\n\n /** Standard info box */\n info: {\n padding: 1,\n margin: { top: 1, bottom: 1, left: 0, right: 0 },\n borderStyle: 'round' as const,\n borderColor: 'cyan' as const,\n },\n\n /** Success box */\n success: {\n padding: 1,\n margin: { top: 1, bottom: 1, left: 0, right: 0 },\n borderStyle: 'round' as const,\n borderColor: 'green' as const,\n },\n\n /** Error box */\n error: {\n padding: 1,\n margin: { top: 1, bottom: 1, left: 0, right: 0 },\n borderStyle: 'round' as const,\n borderColor: 'red' as const,\n },\n};\n","/**\n * Banner and box utilities for tuck CLI\n * Provides ASCII art banner and styled boxes\n */\n\nimport boxen from 'boxen';\nimport { colors as c, boxStyles, indent } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ASCII Art Banner (only for init and help)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const banner = (): void => {\n const art = `\n ████████╗██╗ ██╗ ██████╗██╗ ██╗\n ╚══██╔══╝██║ ██║██╔════╝██║ ██╔╝\n ██║ ██║ ██║██║ █████╔╝ \n ██║ ██║ ██║██║ ██╔═██╗ \n ██║ ╚██████╔╝╚██████╗██║ ██╗\n ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝`;\n\n console.log(c.brand(art));\n console.log(c.muted(' Modern Dotfiles Manager\\n'));\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Mini Banner (compact version for other contexts)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const miniBanner = (): void => {\n console.log(boxen(c.brandBold('tuck') + c.muted(' · Modern Dotfiles Manager'), boxStyles.header));\n console.log();\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Help Text\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const customHelp = (version: string): string => {\n const title = boxen(c.brandBold('tuck') + c.muted(` v${version}`), boxStyles.header);\n\n const quickStart = `\n${c.brandBold('Quick Start:')}\n${indent()}${c.brand('tuck init')} Set up tuck\n${indent()}${c.brand('tuck add <file>')} Track a dotfile\n${indent()}${c.brand('tuck sync')} Commit changes\n${indent()}${c.brand('tuck push')} Push to remote\n\n${c.brandBold('New Machine:')}\n${indent()}${c.brand('tuck apply <user>')} Apply dotfiles from GitHub\n`;\n\n const commands = `\n${c.brandBold('Commands:')}\n${indent()}${c.brand('Getting Started')}\n${indent()}${indent()}init Initialize tuck\n${indent()}${indent()}scan Detect dotfiles\n${indent()}${indent()}apply <source> Apply from repo\n\n${indent()}${c.brand('Managing Files')}\n${indent()}${indent()}add <paths...> Track files\n${indent()}${indent()}remove <paths...> Untrack files\n${indent()}${indent()}list List tracked\n${indent()}${indent()}status Show status\n\n${indent()}${c.brand('Syncing')}\n${indent()}${indent()}sync Commit changes\n${indent()}${indent()}push Push to remote\n${indent()}${indent()}pull Pull from remote\n${indent()}${indent()}diff Show changes\n\n${indent()}${c.brand('Restoring')}\n${indent()}${indent()}restore Restore files\n${indent()}${indent()}undo Undo last apply\n\n${indent()}${c.brand('Config')}\n${indent()}${indent()}config Manage settings\n`;\n\n const footer = `\n${c.muted('Run')} ${c.brand('tuck <command> --help')} ${c.muted('for details')}\n${c.muted('Docs:')} ${c.brand('https://github.com/Pranav-Karra-3301/tuck')}\n`;\n\n return `${title}\\n${quickStart}${commands}${footer}`;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Styled Boxes\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const welcomeBox = (message: string, title?: string): void => {\n console.log(\n boxen(message, {\n ...boxStyles.info,\n title,\n titleAlignment: 'center',\n })\n );\n};\n\nexport const successBox = (message: string, title?: string): void => {\n console.log(\n boxen(message, {\n ...boxStyles.success,\n title: title || 'Success',\n titleAlignment: 'center',\n })\n );\n};\n\nexport const errorBox = (message: string, title?: string): void => {\n console.log(\n boxen(message, {\n ...boxStyles.error,\n title: title || 'Error',\n titleAlignment: 'center',\n })\n );\n};\n\nexport const infoBox = (message: string, title?: string): void => {\n console.log(\n boxen(message, {\n ...boxStyles.info,\n title,\n titleAlignment: 'center',\n })\n );\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Next Steps Box\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const nextSteps = (steps: string[]): void => {\n const content = steps.map((step, i) => `${c.brand(`${i + 1}.`)} ${step}`).join('\\n');\n\n console.log(\n boxen(content, {\n padding: 1,\n margin: { top: 1, bottom: 0, left: 0, right: 0 },\n borderStyle: 'round',\n borderColor: 'cyan',\n title: 'Next Steps',\n titleAlignment: 'left',\n })\n );\n};\n","/**\n * Logger utilities for tuck CLI\n * Provides consistent, styled logging output\n */\n\nimport logSymbols from 'log-symbols';\nimport figures from 'figures';\nimport { colors as c, indent as ind, divider, DIVIDER_WIDTH } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Logger {\n info: (msg: string) => void;\n success: (msg: string) => void;\n warning: (msg: string) => void;\n error: (msg: string) => void;\n debug: (msg: string) => void;\n step: (current: number, total: number, msg: string) => void;\n file: (action: 'add' | 'modify' | 'delete' | 'sync' | 'merge', path: string) => void;\n tree: (items: TreeItem[]) => void;\n blank: () => void;\n dim: (msg: string) => void;\n heading: (msg: string) => void;\n divider: () => void;\n}\n\nexport interface TreeItem {\n name: string;\n isLast: boolean;\n indent?: number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// File Action Icons\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst fileIcons = {\n add: c.success(figures.tick),\n modify: c.warning('~'),\n delete: c.error(figures.cross),\n sync: c.brand(figures.arrowRight),\n merge: c.info('+'),\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Logger Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const logger: Logger = {\n info: (msg: string) => {\n console.log(logSymbols.info, msg);\n },\n\n success: (msg: string) => {\n console.log(logSymbols.success, msg);\n },\n\n warning: (msg: string) => {\n console.log(logSymbols.warning, msg);\n },\n\n error: (msg: string) => {\n console.log(logSymbols.error, msg);\n },\n\n debug: (msg: string) => {\n if (process.env.DEBUG) {\n console.log(c.muted(figures.bullet), c.muted(msg));\n }\n },\n\n step: (current: number, total: number, msg: string) => {\n const counter = c.muted(`[${current}/${total}]`);\n console.log(counter, msg);\n },\n\n file: (action: 'add' | 'modify' | 'delete' | 'sync' | 'merge', path: string) => {\n const icon = fileIcons[action];\n console.log(`${ind()}${icon} ${c.brand(path)}`);\n },\n\n tree: (items: TreeItem[]) => {\n items.forEach(({ name, isLast, indent = 0 }) => {\n const indentation = ind(indent);\n const prefix = isLast ? figures.lineUpRight : figures.lineDownRightArc;\n console.log(c.muted(indentation + prefix + figures.line), name);\n });\n },\n\n blank: () => {\n console.log();\n },\n\n dim: (msg: string) => {\n console.log(c.muted(msg));\n },\n\n heading: (msg: string) => {\n console.log(c.brandBold(msg));\n },\n\n divider: () => {\n console.log(divider(DIVIDER_WIDTH));\n },\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Formatting Helpers (re-exported from theme for convenience)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport { formatPath, formatCategory, formatCount, formatStatus } from './theme.js';\n","/**\n * Prompts wrapper for tuck CLI\n * Uses @clack/prompts for consistent, beautiful interactive prompts\n */\n\nimport * as p from '@clack/prompts';\nimport { colors as c } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SelectOption<T> {\n value: T;\n label: string;\n hint?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Main Prompts Object\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const prompts = {\n /**\n * Display command intro header\n */\n intro: (title: string): void => {\n p.intro(c.brandBg(` ${title} `));\n },\n\n /**\n * Display command outro/success message\n */\n outro: (message: string): void => {\n p.outro(c.success(message));\n },\n\n /**\n * Confirm dialog (yes/no)\n */\n confirm: async (message: string, initial = false): Promise<boolean> => {\n const result = await p.confirm({ message, initialValue: initial });\n if (p.isCancel(result)) {\n prompts.cancel();\n }\n return result as boolean;\n },\n\n /**\n * Single select from options\n */\n select: async <T>(message: string, options: SelectOption<T>[]): Promise<T> => {\n const result = await p.select({\n message,\n options: options.map((opt) => ({\n value: opt.value,\n label: opt.label,\n hint: opt.hint,\n })),\n });\n if (p.isCancel(result)) {\n prompts.cancel();\n }\n return result as T;\n },\n\n /**\n * Multi-select from options\n */\n multiselect: async <T>(\n message: string,\n options: SelectOption<T>[],\n config?: {\n required?: boolean;\n initialValues?: T[];\n }\n ): Promise<T[]> => {\n const mappedOptions = options.map((opt) => ({\n value: opt.value,\n label: opt.label,\n hint: opt.hint ?? '',\n }));\n\n const result = await p.multiselect({\n message,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options: mappedOptions as any,\n required: config?.required ?? false,\n initialValues: config?.initialValues,\n });\n if (p.isCancel(result)) {\n prompts.cancel();\n }\n return result as T[];\n },\n\n /**\n * Text input\n */\n text: async (\n message: string,\n options?: {\n placeholder?: string;\n defaultValue?: string;\n validate?: (value: string) => string | undefined;\n }\n ): Promise<string> => {\n const result = await p.text({\n message,\n placeholder: options?.placeholder,\n defaultValue: options?.defaultValue,\n validate: options?.validate,\n });\n if (p.isCancel(result)) {\n prompts.cancel();\n }\n return result as string;\n },\n\n /**\n * Password input (hidden)\n */\n password: async (message: string): Promise<string> => {\n const result = await p.password({ message });\n if (p.isCancel(result)) {\n prompts.cancel();\n }\n return result as string;\n },\n\n /**\n * Create a spinner for async operations\n */\n spinner: () => p.spinner(),\n\n /**\n * Display a note/info box\n */\n note: (message: string, title?: string): void => {\n p.note(message, title);\n },\n\n /**\n * Cancel operation and exit\n */\n cancel: (message = 'Operation cancelled'): never => {\n p.cancel(message);\n process.exit(0);\n },\n\n /**\n * Logging helpers\n */\n log: {\n info: (message: string): void => {\n p.log.info(message);\n },\n success: (message: string): void => {\n p.log.success(message);\n },\n warning: (message: string): void => {\n p.log.warning(message);\n },\n error: (message: string): void => {\n p.log.error(message);\n },\n step: (message: string): void => {\n p.log.step(message);\n },\n message: (message: string): void => {\n p.log.message(message);\n },\n },\n\n /**\n * Group multiple prompts\n */\n group: async <T>(\n steps: Record<string, () => Promise<T | symbol>>,\n options?: { onCancel?: () => void }\n ): Promise<Record<string, T>> => {\n const results = await p.group(steps, {\n onCancel: () => {\n if (options?.onCancel) {\n options.onCancel();\n } else {\n prompts.cancel();\n }\n },\n });\n return results as Record<string, T>;\n },\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Utility Exports\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const isCancel = p.isCancel;\n","/**\n * Spinner utilities for tuck CLI\n * Uses @clack/prompts spinner as the primary implementation\n * Provides backward-compatible API with enhanced methods\n */\n\nimport * as p from '@clack/prompts';\nimport logSymbols from 'log-symbols';\nimport { colors as c } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SpinnerInstance {\n start: (text?: string) => void;\n stop: () => void;\n succeed: (text?: string) => void;\n fail: (text?: string) => void;\n warn: (text?: string) => void;\n info: (text?: string) => void;\n text: (text: string) => void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Create Spinner\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Create a spinner instance using @clack/prompts\n * Provides ora-compatible API for backward compatibility\n */\nexport const createSpinner = (initialText?: string): SpinnerInstance => {\n const spinner = p.spinner();\n let currentText = initialText || '';\n let started = false;\n\n return {\n start: (text?: string) => {\n currentText = text || currentText || 'Loading...';\n spinner.start(currentText);\n started = true;\n },\n\n stop: () => {\n if (started) {\n spinner.stop(currentText);\n started = false;\n }\n },\n\n succeed: (text?: string) => {\n if (started) {\n spinner.stop(c.success(text || currentText));\n started = false;\n } else {\n console.log(logSymbols.success, c.success(text || currentText));\n }\n },\n\n fail: (text?: string) => {\n if (started) {\n spinner.stop(c.error(text || currentText));\n started = false;\n } else {\n console.log(logSymbols.error, c.error(text || currentText));\n }\n },\n\n warn: (text?: string) => {\n if (started) {\n spinner.stop(c.warning(text || currentText));\n started = false;\n } else {\n console.log(logSymbols.warning, c.warning(text || currentText));\n }\n },\n\n info: (text?: string) => {\n if (started) {\n spinner.stop(c.info(text || currentText));\n started = false;\n } else {\n console.log(logSymbols.info, c.info(text || currentText));\n }\n },\n\n text: (text: string) => {\n currentText = text;\n if (started) {\n spinner.message(text);\n }\n },\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// With Spinner Helper\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Execute an async function with a spinner\n * Automatically shows success/failure based on result\n */\nexport const withSpinner = async <T>(\n text: string,\n fn: () => Promise<T>,\n options?: {\n successText?: string;\n failText?: string;\n }\n): Promise<T> => {\n const spinner = createSpinner(text);\n spinner.start();\n\n try {\n const result = await fn();\n spinner.succeed(options?.successText || text);\n return result;\n } catch (error) {\n spinner.fail(options?.failText || text);\n throw error;\n }\n};\n","/**\n * Table utilities for tuck CLI\n * Provides formatted table output\n */\n\nimport { colors as c } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TableColumn {\n header: string;\n key: string;\n width?: number;\n align?: 'left' | 'right' | 'center';\n format?: (value: unknown) => string;\n}\n\nexport interface TableOptions {\n columns: TableColumn[];\n border?: boolean;\n padding?: number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Utilities\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst padString = (\n str: string,\n width: number,\n align: 'left' | 'right' | 'center' = 'left'\n): string => {\n // Strip ANSI codes for length calculation\n // eslint-disable-next-line no-control-regex\n const visibleLength = str.replace(/\\x1b\\[[0-9;]*m/g, '').length;\n const padding = Math.max(0, width - visibleLength);\n\n switch (align) {\n case 'right':\n return ' '.repeat(padding) + str;\n case 'center': {\n const leftPad = Math.floor(padding / 2);\n const rightPad = padding - leftPad;\n return ' '.repeat(leftPad) + str + ' '.repeat(rightPad);\n }\n default:\n return str + ' '.repeat(padding);\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Table Creation\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const createTable = (data: Record<string, unknown>[], options: TableOptions): string => {\n const { columns, border = false, padding = 2 } = options;\n\n // Calculate column widths\n const widths = columns.map((col) => {\n const headerWidth = col.header.length;\n const maxDataWidth = data.reduce((max, row) => {\n const value = col.format ? col.format(row[col.key]) : String(row[col.key] ?? '');\n // eslint-disable-next-line no-control-regex\n const visibleLength = value.replace(/\\x1b\\[[0-9;]*m/g, '').length;\n return Math.max(max, visibleLength);\n }, 0);\n return col.width || Math.max(headerWidth, maxDataWidth);\n });\n\n const lines: string[] = [];\n const pad = ' '.repeat(padding);\n\n // Header row\n const headerRow = columns\n .map((col, i) => c.bold(padString(col.header, widths[i], col.align)))\n .join(pad);\n\n // Border line\n const borderLine = c.muted(widths.map((w) => '─'.repeat(w)).join(pad));\n\n if (border) {\n lines.push(borderLine);\n lines.push(headerRow);\n lines.push(borderLine);\n } else {\n lines.push(headerRow);\n lines.push(borderLine);\n }\n\n // Data rows\n data.forEach((row) => {\n const dataRow = columns\n .map((col, i) => {\n const value = col.format ? col.format(row[col.key]) : String(row[col.key] ?? '');\n return padString(value, widths[i], col.align);\n })\n .join(pad);\n lines.push(dataRow);\n });\n\n if (border) {\n lines.push(borderLine);\n }\n\n return lines.join('\\n');\n};\n\nexport const printTable = (data: Record<string, unknown>[], options: TableOptions): void => {\n console.log(createTable(data, options));\n};\n","/**\n * Progress display utilities for tuck CLI\n * Provides beautiful, adaptive progress displays for file operations\n *\n * Display Modes:\n * - detailed (≤20 files): Show each file with spinner\n * - compact (21-100 files): Progress bar with current file\n * - minimal (>100 files): Spinner with count only\n */\n\nimport * as p from '@clack/prompts';\nimport logSymbols from 'log-symbols';\nimport figures from 'figures';\nimport { colors as c, divider, indent, DIVIDER_WIDTH, getProgressMode } from './theme.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ProgressItem {\n label: string;\n description?: string;\n}\n\nexport interface ProgressTrackerOptions {\n title?: string;\n showIndex?: boolean;\n animationDelay?: number;\n}\n\nexport interface ProgressTracker {\n start: () => void;\n update: (\n index: number,\n status: 'pending' | 'in_progress' | 'completed' | 'error',\n message?: string\n ) => void;\n complete: (message?: string) => void;\n fail: (message?: string) => void;\n}\n\nexport interface FileOperationItem {\n path: string;\n category?: string;\n action: 'tracking' | 'copying' | 'syncing' | 'restoring';\n icon?: string;\n}\n\nexport interface FileOperationOptions {\n delayBetween?: number;\n showCategory?: boolean;\n onProgress?: (current: number, total: number) => void;\n actionVerb?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Progress Bar Component\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst createProgressBarLine = (current: number, total: number, width = 30): string => {\n const percentage = Math.round((current / total) * 100);\n const filled = Math.round((current / total) * width);\n const empty = width - filled;\n\n const bar = c.brand('█').repeat(filled) + c.muted('░').repeat(empty);\n const stats = c.muted(`${current}/${total}`);\n const pct = c.bold(`${percentage}%`);\n\n return `${bar} ${pct} ${stats}`;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Detailed Mode: Show Each File\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst processDetailed = async <T>(\n items: FileOperationItem[],\n processor: (item: FileOperationItem, index: number) => Promise<T>,\n options: FileOperationOptions\n): Promise<T[]> => {\n const { showCategory = true, onProgress, actionVerb, delayBetween = 50 } = options;\n const results: T[] = [];\n const total = items.length;\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const indexStr = c.muted(`[${i + 1}/${total}]`);\n const actionText = actionVerb || getActionText(item.action);\n\n // Show spinner while processing\n const spinner = p.spinner();\n spinner.start(`${indexStr} ${actionText} ${c.brand(item.path)}`);\n\n try {\n const result = await processor(item, i);\n results.push(result);\n\n // Format completion line\n const categoryStr =\n showCategory && item.category ? c.muted(` [${item.icon || ''}${item.category}]`) : '';\n\n spinner.stop(`${logSymbols.success} ${indexStr} ${item.path}${categoryStr}`);\n\n if (onProgress) {\n onProgress(i + 1, total);\n }\n\n // Small delay for visual effect (except last item)\n if (i < items.length - 1 && delayBetween > 0) {\n await sleep(delayBetween);\n }\n } catch (error) {\n spinner.stop(`${logSymbols.error} ${indexStr} ${item.path} ${c.error('failed')}`);\n throw error;\n }\n }\n\n return results;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Compact Mode: Progress Bar + Current File\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst processCompact = async <T>(\n items: FileOperationItem[],\n processor: (item: FileOperationItem, index: number) => Promise<T>,\n options: FileOperationOptions\n): Promise<T[]> => {\n const { onProgress, delayBetween = 10 } = options;\n const results: T[] = [];\n const total = items.length;\n\n // Track if we've written output that needs clearing\n let hasOutput = false;\n\n const clearLines = () => {\n if (hasOutput) {\n // Move cursor up one line, clear it, move up again, clear it\n process.stdout.write('\\x1b[1A\\x1b[2K\\x1b[1A\\x1b[2K');\n }\n };\n\n const writeProgress = (progressBar: string, currentFile: string) => {\n if (hasOutput) {\n clearLines();\n }\n console.log(`${indent()}${progressBar}`);\n console.log(`${indent()}${c.brand(figures.pointer)} ${currentFile}`);\n hasOutput = true;\n };\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n\n // Show progress bar + current file\n const progressBar = createProgressBarLine(i, total);\n const currentFile = c.muted(truncatePath(item.path, 40));\n writeProgress(progressBar, currentFile);\n\n try {\n const result = await processor(item, i);\n results.push(result);\n\n if (onProgress) {\n onProgress(i + 1, total);\n }\n\n if (delayBetween > 0) {\n await sleep(delayBetween);\n }\n } catch (error) {\n clearLines();\n console.log(`${indent()}${logSymbols.error} ${item.path} ${c.error('failed')}`);\n throw error;\n }\n }\n\n // Final state - clear and show completed progress bar\n clearLines();\n const finalBar = createProgressBarLine(total, total);\n console.log(`${indent()}${finalBar}`);\n\n return results;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Minimal Mode: Spinner with Count\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst processMinimal = async <T>(\n items: FileOperationItem[],\n processor: (item: FileOperationItem, index: number) => Promise<T>,\n options: FileOperationOptions\n): Promise<T[]> => {\n const { actionVerb, onProgress, delayBetween = 5 } = options;\n const results: T[] = [];\n const total = items.length;\n const actionText = actionVerb || 'Processing';\n\n const spinner = p.spinner();\n spinner.start(`${actionText} ${total} files...`);\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const pct = Math.round(((i + 1) / total) * 100);\n\n spinner.message(`${actionText}... ${i + 1}/${total} (${pct}%)`);\n\n try {\n const result = await processor(item, i);\n results.push(result);\n\n if (onProgress) {\n onProgress(i + 1, total);\n }\n\n if (delayBetween > 0 && i < items.length - 1) {\n await sleep(delayBetween);\n }\n } catch (error) {\n spinner.stop(`${logSymbols.error} Failed at ${item.path}`);\n throw error;\n }\n }\n\n spinner.stop(`${logSymbols.success} ${actionText} complete`);\n return results;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Main Entry Point\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Process files with adaptive progress display\n * Automatically selects the best display mode based on item count\n */\nexport const processFilesWithProgress = async <T>(\n items: FileOperationItem[],\n processor: (item: FileOperationItem, index: number) => Promise<T>,\n options: FileOperationOptions = {}\n): Promise<T[]> => {\n const { actionVerb } = options;\n const total = items.length;\n const mode = getProgressMode(total);\n\n // Header\n const displayAction = actionVerb || getActionText(items[0]?.action || 'tracking');\n console.log();\n console.log(c.brandBold(`${displayAction} ${total} ${total === 1 ? 'file' : 'files'}...`));\n console.log(divider(DIVIDER_WIDTH));\n console.log();\n\n // Process based on mode\n let results: T[];\n\n switch (mode) {\n case 'detailed':\n results = await processDetailed(items, processor, options);\n break;\n case 'compact':\n results = await processCompact(items, processor, options);\n break;\n case 'minimal':\n results = await processMinimal(items, processor, options);\n break;\n }\n\n // Summary\n console.log();\n const pastTense = getPastTense(displayAction);\n console.log(\n logSymbols.success,\n c.bold(`${pastTense} ${total} ${total === 1 ? 'file' : 'files'}`)\n );\n\n return results;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Legacy Exports (backward compatibility)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** @deprecated Use processFilesWithProgress instead */\nexport const trackFilesWithProgress = processFilesWithProgress;\n\n/** @deprecated Use FileOperationItem instead */\nexport type FileTrackingItem = FileOperationItem;\n\n/** @deprecated Use FileOperationOptions instead */\nexport type FileTrackingOptions = FileOperationOptions;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Step Progress (for multi-step operations)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface StepProgress {\n start: (text: string) => void;\n succeed: (text?: string) => void;\n fail: (text?: string) => void;\n skip: (text?: string) => void;\n}\n\nexport const createStepProgress = (totalSteps: number): StepProgress => {\n let currentStep = 0;\n let spinner: ReturnType<typeof p.spinner> | null = null;\n let currentText = '';\n\n return {\n start: (text: string) => {\n currentStep++;\n currentText = text;\n const stepStr = c.muted(`[${currentStep}/${totalSteps}]`);\n spinner = p.spinner();\n spinner.start(`${stepStr} ${text}`);\n },\n\n succeed: (text?: string) => {\n if (spinner) {\n const stepStr = c.muted(`[${currentStep}/${totalSteps}]`);\n spinner.stop(`${logSymbols.success} ${stepStr} ${text || currentText}`);\n spinner = null;\n }\n },\n\n fail: (text?: string) => {\n if (spinner) {\n const stepStr = c.muted(`[${currentStep}/${totalSteps}]`);\n spinner.stop(`${logSymbols.error} ${stepStr} ${text || currentText}`);\n spinner = null;\n }\n },\n\n skip: (text?: string) => {\n if (spinner) {\n const stepStr = c.muted(`[${currentStep}/${totalSteps}]`);\n spinner.stop(\n `${logSymbols.info} ${stepStr} ${text || currentText} ${c.muted('(skipped)')}`\n );\n spinner = null;\n }\n },\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Simple Progress Bar\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const createProgressBar = (\n total: number,\n options: { width?: number; label?: string } = {}\n): { update: (current: number, label?: string) => void; complete: () => void } => {\n const { width = 30, label = 'Progress' } = options;\n let lastOutput = '';\n\n const render = (current: number, currentLabel?: string) => {\n const bar = createProgressBarLine(current, total, width);\n const labelStr = currentLabel || label;\n const output = `${indent()}${bar} ${labelStr}`;\n\n // Clear previous line and write new one\n if (lastOutput) {\n process.stdout.write('\\r' + ' '.repeat(lastOutput.length) + '\\r');\n }\n process.stdout.write(output);\n lastOutput = output;\n };\n\n return {\n update: (current: number, currentLabel?: string) => {\n render(current, currentLabel);\n },\n complete: () => {\n if (lastOutput) {\n process.stdout.write('\\r' + ' '.repeat(lastOutput.length) + '\\r');\n }\n console.log(`${indent()}${logSymbols.success} ${label} complete`);\n },\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Operation Summary\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const showOperationSummary = (\n stats: {\n tracked?: number;\n copied?: number;\n synced?: number;\n failed?: number;\n skipped?: number;\n },\n title = 'Summary'\n): void => {\n console.log();\n console.log(c.brandBold(`${title}:`));\n\n if (stats.tracked !== undefined && stats.tracked > 0) {\n console.log(\n `${indent()}${logSymbols.success} Tracked: ${stats.tracked} ${stats.tracked === 1 ? 'file' : 'files'}`\n );\n }\n if (stats.copied !== undefined && stats.copied > 0) {\n console.log(\n `${indent()}${logSymbols.success} Copied: ${stats.copied} ${stats.copied === 1 ? 'file' : 'files'}`\n );\n }\n if (stats.synced !== undefined && stats.synced > 0) {\n console.log(\n `${indent()}${logSymbols.success} Synced: ${stats.synced} ${stats.synced === 1 ? 'file' : 'files'}`\n );\n }\n if (stats.skipped !== undefined && stats.skipped > 0) {\n console.log(\n `${indent()}${c.muted(figures.circle)} Skipped: ${stats.skipped} ${stats.skipped === 1 ? 'file' : 'files'}`\n );\n }\n if (stats.failed !== undefined && stats.failed > 0) {\n console.log(\n `${indent()}${logSymbols.error} Failed: ${stats.failed} ${stats.failed === 1 ? 'file' : 'files'}`\n );\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Utilities\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst getActionText = (action: string): string => {\n const texts: Record<string, string> = {\n tracking: 'Tracking',\n copying: 'Copying',\n syncing: 'Syncing',\n restoring: 'Restoring',\n };\n return texts[action] || 'Processing';\n};\n\nconst getPastTense = (verb: string): string => {\n if (verb.endsWith('ing')) {\n const base = verb.slice(0, -3);\n // Handle consonant + y -> ied (e.g., Copy -> Copied)\n if (base.endsWith('y') && base.length > 1) {\n const beforeY = base[base.length - 2];\n // Check if preceded by consonant (not a vowel)\n if (!'aeiouAEIOU'.includes(beforeY)) {\n return base.slice(0, -1) + 'ied';\n }\n }\n // Handle words ending in 'e' that was dropped (e.g., Sync -> Synced)\n // Most -ing words just need +ed on the base\n return base + 'ed';\n }\n return verb;\n};\n\nconst truncatePath = (path: string, maxLength: number): string => {\n if (path.length <= maxLength) return path;\n return '...' + path.slice(-(maxLength - 3));\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Legacy Progress Tracker (for backward compatibility)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const createProgressTracker = (\n items: ProgressItem[],\n options: ProgressTrackerOptions = {}\n): ProgressTracker => {\n const { title, showIndex = true } = options;\n const total = items.length;\n const statuses: ('pending' | 'in_progress' | 'completed' | 'error')[] = items.map(\n () => 'pending'\n );\n let spinner: ReturnType<typeof p.spinner> | null = null;\n let currentIndex = -1;\n\n const getIcon = (status: 'pending' | 'in_progress' | 'completed' | 'error'): string => {\n switch (status) {\n case 'pending':\n return c.muted(figures.circle);\n case 'in_progress':\n return c.brand(figures.circleFilled);\n case 'completed':\n return logSymbols.success;\n case 'error':\n return logSymbols.error;\n }\n };\n\n const renderLine = (index: number): string => {\n const item = items[index];\n const status = statuses[index];\n const icon = getIcon(status);\n const indexStr = showIndex ? c.muted(`[${index + 1}/${total}]`) + ' ' : '';\n\n let line = `${indent()}${icon} ${indexStr}${item.label}`;\n\n if (item.description && status !== 'in_progress') {\n line += c.muted(` - ${item.description}`);\n }\n\n return line;\n };\n\n return {\n start: () => {\n if (title) {\n console.log();\n console.log(c.brandBold(title));\n console.log(divider(DIVIDER_WIDTH));\n }\n },\n\n update: (\n index: number,\n status: 'pending' | 'in_progress' | 'completed' | 'error',\n message?: string\n ) => {\n statuses[index] = status;\n\n if (status === 'in_progress') {\n if (spinner) {\n spinner.stop();\n }\n\n currentIndex = index;\n const item = items[index];\n const indexStr = showIndex ? c.muted(`[${index + 1}/${total}]`) + ' ' : '';\n\n spinner = p.spinner();\n spinner.start(`${indexStr}${message || item.label}`);\n } else if (status === 'completed' || status === 'error') {\n if (spinner && currentIndex === index) {\n spinner.stop(renderLine(index));\n spinner = null;\n } else {\n console.log(renderLine(index));\n }\n }\n },\n\n complete: (message?: string) => {\n if (spinner) {\n spinner.stop();\n spinner = null;\n }\n console.log();\n console.log(logSymbols.success, message || 'Completed successfully');\n },\n\n fail: (message?: string) => {\n if (spinner) {\n spinner.stop();\n spinner = null;\n }\n console.log();\n console.log(logSymbols.error, message || 'Operation failed');\n },\n };\n};\n","/**\n * UI module exports for tuck CLI\n */\n\n// Theme system (design tokens, colors, icons)\nexport * from './theme.js';\n\n// Components\nexport * from './banner.js';\nexport * from './logger.js';\nexport * from './prompts.js';\nexport * from './spinner.js';\nexport * from './table.js';\nexport * from './progress.js';\n","import { homedir } from 'os';\nimport { join, dirname } from 'path';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport figures from 'figures';\n\n// Read version from package.json at runtime\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst packageJsonPath = join(__dirname, '..', 'package.json');\nlet VERSION_VALUE = '1.0.0'; // fallback\ntry {\n const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n VERSION_VALUE = pkg.version;\n} catch {\n // Fallback if package.json can't be read (e.g., bundled)\n}\nexport const VERSION = VERSION_VALUE;\nexport const DESCRIPTION = 'Modern dotfiles manager with a beautiful CLI';\nexport const APP_NAME = 'tuck';\n\nexport const HOME_DIR = homedir();\nexport const DEFAULT_TUCK_DIR = join(HOME_DIR, '.tuck');\nexport const MANIFEST_FILE = '.tuckmanifest.json';\nexport const CONFIG_FILE = '.tuckrc.json';\nexport const BACKUP_DIR = join(HOME_DIR, '.tuck-backups');\nexport const FILES_DIR = 'files';\n\nexport const MANIFEST_VERSION = '1.0.0';\n\nexport interface CategoryConfig {\n patterns: string[];\n icon: string;\n}\n\nexport const CATEGORIES: Record<string, CategoryConfig> = {\n shell: {\n patterns: [\n '.zshrc',\n '.bashrc',\n '.bash_profile',\n '.zprofile',\n '.profile',\n '.aliases',\n '.zshenv',\n '.bash_aliases',\n '.inputrc',\n ],\n icon: '$',\n },\n git: {\n patterns: ['.gitconfig', '.gitignore_global', '.gitmessage', '.gitattributes'],\n icon: figures.star,\n },\n editors: {\n patterns: [\n '.vimrc',\n '.config/nvim',\n '.emacs',\n '.emacs.d',\n '.config/Code',\n '.ideavimrc',\n '.nanorc',\n ],\n icon: figures.pointer,\n },\n terminal: {\n patterns: [\n '.tmux.conf',\n '.config/alacritty',\n '.config/kitty',\n '.wezterm.lua',\n '.config/wezterm',\n '.config/hyper',\n '.config/starship.toml',\n ],\n icon: '#',\n },\n ssh: {\n patterns: ['.ssh/config'],\n icon: figures.warning,\n },\n misc: {\n patterns: [],\n icon: figures.bullet,\n },\n};\n\nexport const COMMON_DOTFILES = [\n { path: '~/.zshrc', category: 'shell' },\n { path: '~/.bashrc', category: 'shell' },\n { path: '~/.bash_profile', category: 'shell' },\n { path: '~/.gitconfig', category: 'git' },\n { path: '~/.config/nvim', category: 'editors' },\n { path: '~/.vimrc', category: 'editors' },\n { path: '~/.tmux.conf', category: 'terminal' },\n { path: '~/.ssh/config', category: 'ssh' },\n { path: '~/.config/starship.toml', category: 'terminal' },\n];\n","import { homedir } from 'os';\nimport { join, basename, dirname, relative, isAbsolute, resolve, sep } from 'path';\nimport { stat, access } from 'fs/promises';\nimport { constants } from 'fs';\nimport { DEFAULT_TUCK_DIR, FILES_DIR, MANIFEST_FILE, CONFIG_FILE, CATEGORIES } from '../constants.js';\n\nexport const expandPath = (path: string): string => {\n if (path.startsWith('~/')) {\n return join(homedir(), path.slice(2));\n }\n if (path.startsWith('$HOME/')) {\n return join(homedir(), path.slice(6));\n }\n return isAbsolute(path) ? path : resolve(path);\n};\n\nexport const collapsePath = (path: string): string => {\n const home = homedir();\n if (path.startsWith(home)) {\n return '~' + path.slice(home.length);\n }\n return path;\n};\n\nexport const getTuckDir = (customDir?: string): string => {\n return expandPath(customDir || DEFAULT_TUCK_DIR);\n};\n\nexport const getManifestPath = (tuckDir: string): string => {\n return join(tuckDir, MANIFEST_FILE);\n};\n\nexport const getConfigPath = (tuckDir: string): string => {\n return join(tuckDir, CONFIG_FILE);\n};\n\nexport const getFilesDir = (tuckDir: string): string => {\n return join(tuckDir, FILES_DIR);\n};\n\nexport const getCategoryDir = (tuckDir: string, category: string): string => {\n return join(getFilesDir(tuckDir), category);\n};\n\nexport const getDestinationPath = (tuckDir: string, category: string, filename: string): string => {\n return join(getCategoryDir(tuckDir, category), filename);\n};\n\nexport const getRelativeDestination = (category: string, filename: string): string => {\n return join(FILES_DIR, category, filename);\n};\n\nexport const sanitizeFilename = (filepath: string): string => {\n const base = basename(filepath);\n // Remove leading dot for storage, but keep track that it was a dotfile\n return base.startsWith('.') ? base.slice(1) : base;\n};\n\nexport const detectCategory = (filepath: string): string => {\n const expandedPath = expandPath(filepath);\n const relativePath = collapsePath(expandedPath);\n\n for (const [category, config] of Object.entries(CATEGORIES)) {\n for (const pattern of config.patterns) {\n // Check if the pattern matches the path\n if (relativePath.endsWith(pattern) || relativePath.includes(pattern)) {\n return category;\n }\n // Check just the filename\n const filename = basename(expandedPath);\n if (filename === pattern || filename === basename(pattern)) {\n return category;\n }\n }\n }\n\n return 'misc';\n};\n\nexport const pathExists = async (path: string): Promise<boolean> => {\n try {\n await access(path, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n};\n\nexport const isDirectory = async (path: string): Promise<boolean> => {\n try {\n const stats = await stat(path);\n return stats.isDirectory();\n } catch {\n return false;\n }\n};\n\nexport const isFile = async (path: string): Promise<boolean> => {\n try {\n const stats = await stat(path);\n return stats.isFile();\n } catch {\n return false;\n }\n};\n\nexport const isSymlink = async (path: string): Promise<boolean> => {\n try {\n const stats = await stat(path);\n return stats.isSymbolicLink();\n } catch {\n return false;\n }\n};\n\nexport const isReadable = async (path: string): Promise<boolean> => {\n try {\n await access(path, constants.R_OK);\n return true;\n } catch {\n return false;\n }\n};\n\nexport const isWritable = async (path: string): Promise<boolean> => {\n try {\n await access(path, constants.W_OK);\n return true;\n } catch {\n return false;\n }\n};\n\nexport const getRelativePath = (from: string, to: string): string => {\n return relative(dirname(from), to);\n};\n\n/**\n * Validate that a path is safely within the user's home directory.\n * Prevents path traversal attacks from malicious manifests.\n * @returns true if the path is within home directory, false otherwise\n */\nexport const isPathWithinHome = (path: string): boolean => {\n const home = homedir();\n const expandedPath = expandPath(path);\n const normalizedPath = resolve(expandedPath);\n const normalizedHome = resolve(home);\n\n // Check if the normalized path starts with the home directory\n // Use path.sep for cross-platform compatibility (/ on POSIX, \\ on Windows)\n return normalizedPath.startsWith(normalizedHome + sep) || normalizedPath === normalizedHome;\n};\n\n/**\n * Validate that a source path from a manifest is safe to use.\n * Throws an error if the path is unsafe (path traversal attempt).\n */\nexport const validateSafeSourcePath = (source: string): void => {\n // Reject absolute paths that don't start with home-relative prefixes\n if (isAbsolute(source) && !source.startsWith(homedir())) {\n throw new Error(`Unsafe path detected: ${source} - absolute paths outside home directory are not allowed`);\n }\n\n // Reject obvious path traversal attempts\n if (source.includes('../') || source.includes('..\\\\')) {\n throw new Error(`Unsafe path detected: ${source} - path traversal is not allowed`);\n }\n\n // Validate the expanded path is within home\n if (!isPathWithinHome(source)) {\n throw new Error(`Unsafe path detected: ${source} - paths must be within home directory`);\n }\n};\n\nexport const generateFileId = (source: string): string => {\n // Create a unique ID from the source path\n const collapsed = collapsePath(source);\n // Remove special characters and create a readable ID\n return collapsed\n .replace(/^~\\//, '')\n .replace(/\\//g, '_')\n .replace(/\\./g, '-')\n .replace(/^-/, '');\n};\n","/**\n * Zod schemas for secret scanning configuration\n */\n\nimport { z } from 'zod';\n\n/**\n * Schema for custom secret patterns defined by users\n */\nexport const customPatternSchema = z.object({\n name: z.string().optional(),\n pattern: z.string(),\n severity: z.enum(['critical', 'high', 'medium', 'low']).optional().default('high'),\n description: z.string().optional(),\n placeholder: z.string().optional(),\n flags: z.string().optional().default('g'),\n});\n\n/**\n * Schema for security configuration\n */\nexport const securityConfigSchema = z\n .object({\n // Enable/disable secret scanning\n scanSecrets: z.boolean().default(true),\n\n // Block operations when secrets are detected (vs just warn)\n blockOnSecrets: z.boolean().default(true),\n\n // Minimum severity level to report\n minSeverity: z.enum(['critical', 'high', 'medium', 'low']).default('high'),\n\n // Scanner to use: 'builtin' or external tools\n scanner: z.enum(['builtin', 'gitleaks', 'trufflehog']).default('builtin'),\n\n // Path to gitleaks binary (if using gitleaks scanner)\n gitleaksPath: z.string().optional(),\n\n // Path to trufflehog binary (if using trufflehog scanner)\n trufflehogPath: z.string().optional(),\n\n // Custom patterns to add to the built-in patterns\n customPatterns: z.array(customPatternSchema).default([]),\n\n // Pattern IDs to exclude from scanning\n excludePatterns: z.array(z.string()).default([]),\n\n // File patterns to exclude from scanning (glob patterns)\n excludeFiles: z.array(z.string()).default([]),\n\n // Maximum file size to scan (in bytes)\n maxFileSize: z.number().default(10 * 1024 * 1024), // 10MB\n })\n .partial()\n .default({});\n\n/**\n * Schema for the secrets store file (secrets.local.json)\n */\nexport const secretEntrySchema = z.object({\n value: z.string(),\n placeholder: z.string(),\n description: z.string().optional(),\n source: z.string().optional(),\n addedAt: z.string(),\n lastUsed: z.string().optional(),\n});\n\nexport const secretsStoreSchema = z.object({\n version: z.string().default('1.0.0'),\n secrets: z.record(secretEntrySchema).default({}),\n});\n\n// Type exports\nexport type CustomPattern = z.infer<typeof customPatternSchema>;\nexport type SecurityConfig = z.infer<typeof securityConfigSchema>;\nexport type SecretEntry = z.infer<typeof secretEntrySchema>;\nexport type SecretsStore = z.infer<typeof secretsStoreSchema>;\n","import { z } from 'zod';\nimport { securityConfigSchema } from './secrets.schema.js';\n\nexport const fileStrategySchema = z.enum(['copy', 'symlink']);\n\n// ============================================================================\n// Remote/Provider Configuration\n// ============================================================================\n\n/** Supported git provider modes */\nexport const providerModeSchema = z.enum(['github', 'gitlab', 'local', 'custom']);\n\n/** Remote configuration schema */\nexport const remoteConfigSchema = z\n .object({\n /** Provider mode (github, gitlab, local, custom) */\n mode: providerModeSchema.default('local'),\n /** Custom remote URL (for custom mode or manual override) */\n url: z.string().optional(),\n /** Provider instance URL (for self-hosted GitLab, etc.) */\n providerUrl: z.string().optional(),\n /** Cached username from provider */\n username: z.string().optional(),\n /** Repository name (without owner) */\n repoName: z.string().optional(),\n })\n .default({ mode: 'local' });\n\nexport const categoryConfigSchema = z.object({\n patterns: z.array(z.string()),\n icon: z.string().optional(),\n});\n\nexport const tuckConfigSchema = z.object({\n repository: z\n .object({\n path: z.string(),\n defaultBranch: z.string().default('main'),\n autoCommit: z.boolean().default(true),\n autoPush: z.boolean().default(false),\n })\n .partial()\n .default({}),\n\n files: z\n .object({\n strategy: fileStrategySchema.default('copy'),\n backupOnRestore: z.boolean().default(true),\n backupDir: z.string().optional(),\n })\n .partial()\n .default({}),\n\n categories: z.record(categoryConfigSchema).optional().default({}),\n\n ignore: z.array(z.string()).optional().default([]),\n\n hooks: z\n .object({\n preSync: z.string().optional(),\n postSync: z.string().optional(),\n preRestore: z.string().optional(),\n postRestore: z.string().optional(),\n })\n .partial()\n .default({}),\n\n templates: z\n .object({\n enabled: z.boolean().default(false),\n variables: z.record(z.string()).default({}),\n })\n .partial()\n .default({}),\n\n encryption: z\n .object({\n enabled: z.boolean().default(false),\n gpgKey: z.string().optional(),\n files: z.array(z.string()).default([]),\n })\n .partial()\n .default({}),\n\n ui: z\n .object({\n colors: z.boolean().default(true),\n emoji: z.boolean().default(true),\n verbose: z.boolean().default(false),\n })\n .partial()\n .default({}),\n\n security: securityConfigSchema,\n\n /** Remote/provider configuration */\n remote: remoteConfigSchema,\n});\n\nexport type TuckConfigInput = z.input<typeof tuckConfigSchema>;\nexport type TuckConfigOutput = z.output<typeof tuckConfigSchema>;\nexport type ProviderMode = z.infer<typeof providerModeSchema>;\nexport type RemoteConfigOutput = z.output<typeof remoteConfigSchema>;\n\nexport const defaultConfig: TuckConfigOutput = {\n repository: {\n defaultBranch: 'main',\n autoCommit: true,\n autoPush: false,\n },\n files: {\n strategy: 'copy',\n backupOnRestore: true,\n },\n categories: {},\n ignore: [],\n hooks: {},\n templates: {\n enabled: false,\n variables: {},\n },\n encryption: {\n enabled: false,\n files: [],\n },\n ui: {\n colors: true,\n emoji: true,\n verbose: false,\n },\n security: {\n scanSecrets: true,\n blockOnSecrets: true,\n minSeverity: 'high',\n scanner: 'builtin',\n customPatterns: [],\n excludePatterns: [],\n excludeFiles: [],\n maxFileSize: 10 * 1024 * 1024,\n },\n remote: {\n mode: 'local',\n },\n};\n","import chalk from 'chalk';\n\nexport class TuckError extends Error {\n constructor(\n message: string,\n public code: string,\n public suggestions?: string[]\n ) {\n super(message);\n this.name = 'TuckError';\n }\n}\n\nexport class NotInitializedError extends TuckError {\n constructor() {\n super('Tuck is not initialized in this system', 'NOT_INITIALIZED', [\n 'Run `tuck init` to get started',\n ]);\n }\n}\n\nexport class AlreadyInitializedError extends TuckError {\n constructor(path: string) {\n super(`Tuck is already initialized at ${path}`, 'ALREADY_INITIALIZED', [\n 'Use `tuck status` to see current state',\n `Remove ${path} to reinitialize`,\n ]);\n }\n}\n\nexport class FileNotFoundError extends TuckError {\n constructor(path: string) {\n super(`File not found: ${path}`, 'FILE_NOT_FOUND', [\n 'Check that the path is correct',\n 'Use absolute paths or paths relative to home directory',\n ]);\n }\n}\n\nexport class FileNotTrackedError extends TuckError {\n constructor(path: string) {\n super(`File is not tracked: ${path}`, 'FILE_NOT_TRACKED', [\n `Run \\`tuck add ${path}\\` to track this file`,\n 'Run `tuck list` to see all tracked files',\n ]);\n }\n}\n\nexport class FileAlreadyTrackedError extends TuckError {\n constructor(path: string) {\n super(`File is already tracked: ${path}`, 'FILE_ALREADY_TRACKED', [\n 'Run `tuck sync` to update it',\n `Run \\`tuck remove ${path}\\` to untrack`,\n ]);\n }\n}\n\nexport class GitError extends TuckError {\n constructor(message: string, gitError?: string) {\n super(`Git operation failed: ${message}`, 'GIT_ERROR', gitError ? [gitError] : undefined);\n }\n}\n\nexport class ConfigError extends TuckError {\n constructor(message: string) {\n super(`Configuration error: ${message}`, 'CONFIG_ERROR', [\n 'Run `tuck config edit` to fix configuration',\n 'Run `tuck config reset` to restore defaults',\n ]);\n }\n}\n\nexport class ManifestError extends TuckError {\n constructor(message: string) {\n super(`Manifest error: ${message}`, 'MANIFEST_ERROR', [\n 'The manifest file may be corrupted',\n 'Run `tuck init --from <remote>` to restore from remote',\n ]);\n }\n}\n\nexport class PermissionError extends TuckError {\n constructor(path: string, operation: string) {\n super(`Permission denied: cannot ${operation} ${path}`, 'PERMISSION_ERROR', [\n 'Check file permissions',\n 'Try running with appropriate permissions',\n ]);\n }\n}\n\nexport class GitHubCliError extends TuckError {\n constructor(message: string, suggestions?: string[]) {\n super(\n `GitHub CLI error: ${message}`,\n 'GITHUB_CLI_ERROR',\n suggestions || ['Install GitHub CLI: https://cli.github.com/', 'Run `gh auth login` to authenticate']\n );\n }\n}\n\nexport class BackupError extends TuckError {\n constructor(message: string, suggestions?: string[]) {\n super(`Backup error: ${message}`, 'BACKUP_ERROR', suggestions || ['Check available disk space']);\n }\n}\n\nexport class SecretsDetectedError extends TuckError {\n constructor(count: number, files: string[]) {\n const fileList = files.slice(0, 3).join(', ') + (files.length > 3 ? ` and ${files.length - 3} more` : '');\n \n // Tailor suggestions based on interactive vs CI/CD context\n const isInteractive = !!process.stdout.isTTY && process.env.CI !== 'true';\n const suggestions = isInteractive\n ? [\n 'Review the detected secrets and choose how to proceed',\n 'Use --force to bypass secret scanning (not recommended)',\n 'Run `tuck secrets list` to see stored secrets',\n 'Configure scanning with `tuck config set security.scanSecrets false`',\n ]\n : [\n 'Review the detected secrets in your source and choose how to proceed before re-running in CI',\n 'Use --force to bypass secret scanning (not recommended) if you are sure the secrets are safe to ignore',\n 'If needed, run `tuck secrets list` in a local interactive environment to inspect stored secrets',\n 'Configure scanning with `tuck config set security.scanSecrets false` if this check is not desired in CI',\n ];\n \n super(`Found ${count} potential secret(s) in: ${fileList}`, 'SECRETS_DETECTED', suggestions);\n }\n}\n\nexport const handleError = (error: unknown): never => {\n if (error instanceof TuckError) {\n console.error(chalk.red('x'), error.message);\n if (error.suggestions && error.suggestions.length > 0) {\n console.error();\n console.error(chalk.dim('Suggestions:'));\n error.suggestions.forEach((s) => console.error(chalk.dim(` → ${s}`)));\n }\n process.exit(1);\n }\n\n if (error instanceof Error) {\n console.error(chalk.red('x'), 'An unexpected error occurred:', error.message);\n if (process.env.DEBUG) {\n console.error(error.stack);\n }\n process.exit(1);\n }\n\n console.error(chalk.red('x'), 'An unknown error occurred');\n process.exit(1);\n};\n","import { readFile, writeFile } from 'fs/promises';\nimport { dirname } from 'path';\nimport { cosmiconfig } from 'cosmiconfig';\nimport { tuckConfigSchema, defaultConfig, type TuckConfigOutput } from '../schemas/config.schema.js';\nimport { getConfigPath, pathExists, getTuckDir } from './paths.js';\nimport { ConfigError } from '../errors.js';\nimport { BACKUP_DIR } from '../constants.js';\n\nlet cachedConfig: TuckConfigOutput | null = null;\nlet cachedTuckDir: string | null = null;\n\nexport const loadConfig = async (tuckDir?: string): Promise<TuckConfigOutput> => {\n const dir = tuckDir || getTuckDir();\n\n // Return cached config if same directory\n if (cachedConfig && cachedTuckDir === dir) {\n return cachedConfig;\n }\n\n const configPath = getConfigPath(dir);\n\n if (!(await pathExists(configPath))) {\n // Return default config if no config file exists\n cachedConfig = { ...defaultConfig, repository: { ...defaultConfig.repository, path: dir } };\n cachedTuckDir = dir;\n return cachedConfig;\n }\n\n try {\n const content = await readFile(configPath, 'utf-8');\n const rawConfig = JSON.parse(content);\n const result = tuckConfigSchema.safeParse(rawConfig);\n\n if (!result.success) {\n throw new ConfigError(`Invalid configuration: ${result.error.message}`);\n }\n\n // Merge with defaults\n cachedConfig = {\n ...defaultConfig,\n ...result.data,\n repository: {\n ...defaultConfig.repository,\n ...result.data.repository,\n path: dir,\n },\n files: {\n ...defaultConfig.files,\n ...result.data.files,\n backupDir: result.data.files?.backupDir || BACKUP_DIR,\n },\n };\n cachedTuckDir = dir;\n\n return cachedConfig;\n } catch (error) {\n if (error instanceof ConfigError) {\n throw error;\n }\n if (error instanceof SyntaxError) {\n throw new ConfigError('Configuration file contains invalid JSON');\n }\n throw new ConfigError(`Failed to load configuration: ${error}`);\n }\n};\n\nexport const saveConfig = async (\n config: Partial<TuckConfigOutput>,\n tuckDir?: string\n): Promise<void> => {\n const dir = tuckDir || getTuckDir();\n const configPath = getConfigPath(dir);\n\n // Load existing config and merge\n const existing = await loadConfig(dir);\n const merged = {\n ...existing,\n ...config,\n repository: {\n ...existing.repository,\n ...config.repository,\n },\n files: {\n ...existing.files,\n ...config.files,\n },\n hooks: {\n ...existing.hooks,\n ...config.hooks,\n },\n templates: {\n ...existing.templates,\n ...config.templates,\n },\n encryption: {\n ...existing.encryption,\n ...config.encryption,\n },\n ui: {\n ...existing.ui,\n ...config.ui,\n },\n };\n\n // Validate before saving\n const result = tuckConfigSchema.safeParse(merged);\n if (!result.success) {\n throw new ConfigError(`Invalid configuration: ${result.error.message}`);\n }\n\n try {\n await writeFile(configPath, JSON.stringify(result.data, null, 2) + '\\n', 'utf-8');\n // Update cache\n cachedConfig = result.data;\n cachedTuckDir = dir;\n } catch (error) {\n throw new ConfigError(`Failed to save configuration: ${error}`);\n }\n};\n\nexport const getConfigValue = async <K extends keyof TuckConfigOutput>(\n key: K,\n tuckDir?: string\n): Promise<TuckConfigOutput[K]> => {\n const config = await loadConfig(tuckDir);\n return config[key];\n};\n\nexport const setConfigValue = async <K extends keyof TuckConfigOutput>(\n key: K,\n value: TuckConfigOutput[K],\n tuckDir?: string\n): Promise<void> => {\n await saveConfig({ [key]: value } as Partial<TuckConfigOutput>, tuckDir);\n};\n\nexport const resetConfig = async (tuckDir?: string): Promise<void> => {\n const dir = tuckDir || getTuckDir();\n const configPath = getConfigPath(dir);\n\n const resetTo = { ...defaultConfig, repository: { ...defaultConfig.repository, path: dir } };\n\n try {\n await writeFile(configPath, JSON.stringify(resetTo, null, 2) + '\\n', 'utf-8');\n cachedConfig = resetTo;\n cachedTuckDir = dir;\n } catch (error) {\n throw new ConfigError(`Failed to reset configuration: ${error}`);\n }\n};\n\nexport const clearConfigCache = (): void => {\n cachedConfig = null;\n cachedTuckDir = null;\n};\n\nexport const findTuckDir = async (): Promise<string | null> => {\n // First check default location\n const defaultDir = getTuckDir();\n if (await pathExists(getConfigPath(defaultDir))) {\n return defaultDir;\n }\n\n // Try cosmiconfig to find config in current directory or parents\n const explorer = cosmiconfig('tuck', {\n searchPlaces: [\n '.tuckrc',\n '.tuckrc.json',\n '.tuckrc.yaml',\n '.tuckrc.yml',\n 'tuck.config.js',\n 'tuck.config.cjs',\n ],\n });\n\n try {\n const result = await explorer.search();\n if (result?.filepath) {\n // Return the directory containing the config file, not the file path itself\n return dirname(result.filepath);\n }\n } catch {\n // Ignore search errors\n }\n\n return null;\n};\n","import { z } from 'zod';\n\nexport const fileStrategySchema = z.enum(['copy', 'symlink']);\n\nexport const trackedFileSchema = z.object({\n source: z.string(),\n destination: z.string(),\n category: z.string(),\n strategy: fileStrategySchema,\n encrypted: z.boolean().default(false),\n template: z.boolean().default(false),\n permissions: z.string().optional(),\n added: z.string(),\n modified: z.string(),\n checksum: z.string(),\n});\n\nexport const tuckManifestSchema = z.object({\n version: z.string(),\n created: z.string(),\n updated: z.string(),\n machine: z.string().optional(),\n files: z.record(trackedFileSchema),\n});\n\nexport type TrackedFileInput = z.input<typeof trackedFileSchema>;\nexport type TrackedFileOutput = z.output<typeof trackedFileSchema>;\nexport type TuckManifestInput = z.input<typeof tuckManifestSchema>;\nexport type TuckManifestOutput = z.output<typeof tuckManifestSchema>;\n\nexport const createEmptyManifest = (machine?: string): TuckManifestOutput => {\n const now = new Date().toISOString();\n return {\n version: '1.0.0',\n created: now,\n updated: now,\n machine,\n files: {},\n };\n};\n","import { readFile, writeFile } from 'fs/promises';\nimport {\n tuckManifestSchema,\n createEmptyManifest,\n type TuckManifestOutput,\n type TrackedFileOutput,\n} from '../schemas/manifest.schema.js';\nimport { getManifestPath, pathExists } from './paths.js';\nimport { ManifestError } from '../errors.js';\n\nlet cachedManifest: TuckManifestOutput | null = null;\nlet cachedManifestDir: string | null = null;\n\nexport const loadManifest = async (tuckDir: string): Promise<TuckManifestOutput> => {\n // Return cached manifest if same directory\n if (cachedManifest && cachedManifestDir === tuckDir) {\n return cachedManifest;\n }\n\n const manifestPath = getManifestPath(tuckDir);\n\n if (!(await pathExists(manifestPath))) {\n throw new ManifestError('Manifest file not found. Is tuck initialized?');\n }\n\n try {\n const content = await readFile(manifestPath, 'utf-8');\n const rawManifest = JSON.parse(content);\n const result = tuckManifestSchema.safeParse(rawManifest);\n\n if (!result.success) {\n throw new ManifestError(`Invalid manifest: ${result.error.message}`);\n }\n\n cachedManifest = result.data;\n cachedManifestDir = tuckDir;\n\n return cachedManifest;\n } catch (error) {\n if (error instanceof ManifestError) {\n throw error;\n }\n if (error instanceof SyntaxError) {\n throw new ManifestError('Manifest file contains invalid JSON');\n }\n throw new ManifestError(`Failed to load manifest: ${error}`);\n }\n};\n\nexport const saveManifest = async (\n manifest: TuckManifestOutput,\n tuckDir: string\n): Promise<void> => {\n const manifestPath = getManifestPath(tuckDir);\n\n // Update the updated timestamp\n manifest.updated = new Date().toISOString();\n\n // Validate before saving\n const result = tuckManifestSchema.safeParse(manifest);\n if (!result.success) {\n throw new ManifestError(`Invalid manifest: ${result.error.message}`);\n }\n\n try {\n await writeFile(manifestPath, JSON.stringify(result.data, null, 2) + '\\n', 'utf-8');\n cachedManifest = result.data;\n cachedManifestDir = tuckDir;\n } catch (error) {\n throw new ManifestError(`Failed to save manifest: ${error}`);\n }\n};\n\nexport const createManifest = async (\n tuckDir: string,\n machine?: string\n): Promise<TuckManifestOutput> => {\n const manifestPath = getManifestPath(tuckDir);\n\n if (await pathExists(manifestPath)) {\n throw new ManifestError('Manifest already exists');\n }\n\n const manifest = createEmptyManifest(machine);\n\n try {\n await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8');\n cachedManifest = manifest;\n cachedManifestDir = tuckDir;\n return manifest;\n } catch (error) {\n throw new ManifestError(`Failed to create manifest: ${error}`);\n }\n};\n\nexport const addFileToManifest = async (\n tuckDir: string,\n id: string,\n file: TrackedFileOutput\n): Promise<void> => {\n const manifest = await loadManifest(tuckDir);\n\n if (manifest.files[id]) {\n throw new ManifestError(`File already tracked with ID: ${id}`);\n }\n\n manifest.files[id] = file;\n await saveManifest(manifest, tuckDir);\n};\n\nexport const updateFileInManifest = async (\n tuckDir: string,\n id: string,\n updates: Partial<TrackedFileOutput>\n): Promise<void> => {\n const manifest = await loadManifest(tuckDir);\n\n if (!manifest.files[id]) {\n throw new ManifestError(`File not found in manifest: ${id}`);\n }\n\n manifest.files[id] = {\n ...manifest.files[id],\n ...updates,\n modified: new Date().toISOString(),\n };\n\n await saveManifest(manifest, tuckDir);\n};\n\nexport const removeFileFromManifest = async (tuckDir: string, id: string): Promise<void> => {\n const manifest = await loadManifest(tuckDir);\n\n if (!manifest.files[id]) {\n throw new ManifestError(`File not found in manifest: ${id}`);\n }\n\n delete manifest.files[id];\n await saveManifest(manifest, tuckDir);\n};\n\nexport const getTrackedFile = async (\n tuckDir: string,\n id: string\n): Promise<TrackedFileOutput | null> => {\n const manifest = await loadManifest(tuckDir);\n return manifest.files[id] || null;\n};\n\nexport const getTrackedFileBySource = async (\n tuckDir: string,\n source: string\n): Promise<{ id: string; file: TrackedFileOutput } | null> => {\n const manifest = await loadManifest(tuckDir);\n\n for (const [id, file] of Object.entries(manifest.files)) {\n if (file.source === source) {\n return { id, file };\n }\n }\n\n return null;\n};\n\nexport const getAllTrackedFiles = async (\n tuckDir: string\n): Promise<Record<string, TrackedFileOutput>> => {\n const manifest = await loadManifest(tuckDir);\n return manifest.files;\n};\n\nexport const getTrackedFilesByCategory = async (\n tuckDir: string,\n category: string\n): Promise<Record<string, TrackedFileOutput>> => {\n const manifest = await loadManifest(tuckDir);\n const filtered: Record<string, TrackedFileOutput> = {};\n\n for (const [id, file] of Object.entries(manifest.files)) {\n if (file.category === category) {\n filtered[id] = file;\n }\n }\n\n return filtered;\n};\n\nexport const isFileTracked = async (tuckDir: string, source: string): Promise<boolean> => {\n const result = await getTrackedFileBySource(tuckDir, source);\n return result !== null;\n};\n\nexport const getFileCount = async (tuckDir: string): Promise<number> => {\n const manifest = await loadManifest(tuckDir);\n return Object.keys(manifest.files).length;\n};\n\nexport const getCategories = async (tuckDir: string): Promise<string[]> => {\n const manifest = await loadManifest(tuckDir);\n const categories = new Set<string>();\n\n for (const file of Object.values(manifest.files)) {\n categories.add(file.category);\n }\n\n return Array.from(categories).sort();\n};\n\nexport const clearManifestCache = (): void => {\n cachedManifest = null;\n cachedManifestDir = null;\n};\n","import simpleGit, { SimpleGit, StatusResult } from 'simple-git';\nimport { GitError } from '../errors.js';\nimport { pathExists } from './paths.js';\nimport { join } from 'path';\n\nexport interface GitStatus {\n isRepo: boolean;\n branch: string;\n tracking?: string;\n ahead: number;\n behind: number;\n staged: string[];\n modified: string[];\n untracked: string[];\n deleted: string[];\n hasChanges: boolean;\n}\n\nexport interface GitCommit {\n hash: string;\n date: string;\n message: string;\n author: string;\n}\n\nconst createGit = (dir: string): SimpleGit => {\n return simpleGit(dir, {\n binary: 'git',\n maxConcurrentProcesses: 6,\n trimmed: true,\n });\n};\n\nexport const isGitRepo = async (dir: string): Promise<boolean> => {\n const gitDir = join(dir, '.git');\n return pathExists(gitDir);\n};\n\nexport const initRepo = async (dir: string): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.init();\n } catch (error) {\n throw new GitError('Failed to initialize repository', String(error));\n }\n};\n\nexport const cloneRepo = async (url: string, dir: string): Promise<void> => {\n try {\n const git = simpleGit();\n await git.clone(url, dir);\n } catch (error) {\n throw new GitError(`Failed to clone repository from ${url}`, String(error));\n }\n};\n\nexport const addRemote = async (dir: string, name: string, url: string): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.addRemote(name, url);\n } catch (error) {\n throw new GitError('Failed to add remote', String(error));\n }\n};\n\nexport const removeRemote = async (dir: string, name: string): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.removeRemote(name);\n } catch (error) {\n throw new GitError('Failed to remove remote', String(error));\n }\n};\n\nexport const getRemotes = async (dir: string): Promise<{ name: string; url: string }[]> => {\n try {\n const git = createGit(dir);\n const remotes = await git.getRemotes(true);\n return remotes.map((r) => ({ name: r.name, url: r.refs.fetch || r.refs.push || '' }));\n } catch (error) {\n throw new GitError('Failed to get remotes', String(error));\n }\n};\n\nexport const getStatus = async (dir: string): Promise<GitStatus> => {\n try {\n const git = createGit(dir);\n const status: StatusResult = await git.status();\n\n return {\n isRepo: true,\n branch: status.current || 'main',\n tracking: status.tracking || undefined,\n ahead: status.ahead,\n behind: status.behind,\n staged: status.staged,\n modified: status.modified,\n untracked: status.not_added,\n deleted: status.deleted,\n hasChanges: !status.isClean(),\n };\n } catch (error) {\n throw new GitError('Failed to get status', String(error));\n }\n};\n\nexport const stageFiles = async (dir: string, files: string[]): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.add(files);\n } catch (error) {\n throw new GitError('Failed to stage files', String(error));\n }\n};\n\nexport const stageAll = async (dir: string): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.add('.');\n } catch (error) {\n throw new GitError('Failed to stage all files', String(error));\n }\n};\n\nexport const commit = async (dir: string, message: string): Promise<string> => {\n try {\n const git = createGit(dir);\n const result = await git.commit(message);\n return result.commit;\n } catch (error) {\n throw new GitError('Failed to commit', String(error));\n }\n};\n\n/**\n * Configure git to use gh CLI credentials if gh is authenticated\n */\nconst ensureGitCredentials = async (): Promise<void> => {\n try {\n // Check if gh is authenticated\n const { execFile } = await import('child_process');\n const { promisify } = await import('util');\n const execFileAsync = promisify(execFile);\n \n const { stdout, stderr } = await execFileAsync('gh', ['auth', 'status']);\n // gh auth status writes its output to stderr per gh CLI design\n const output = (stderr || stdout || '').trim();\n \n if (output.includes('Logged in')) {\n // gh is authenticated, configure git to use it\n await execFileAsync('gh', ['auth', 'setup-git']);\n }\n } catch {\n // gh CLI not available or not authenticated; skip git credential setup.\n // This is expected on systems without gh CLI or when user hasn't logged in.\n // Git will fall back to default credential mechanisms (ssh keys, https tokens, etc.)\n }\n};\n\nexport const push = async (\n dir: string,\n options?: { remote?: string; branch?: string; force?: boolean; setUpstream?: boolean }\n): Promise<void> => {\n try {\n // Ensure git can use gh credentials if available\n await ensureGitCredentials();\n \n const git = createGit(dir);\n const args: string[] = [];\n\n if (options?.setUpstream) {\n args.push('-u');\n }\n if (options?.force) {\n args.push('--force');\n }\n\n const remote = options?.remote || 'origin';\n const branch = options?.branch;\n\n if (branch) {\n await git.push([...args, remote, branch]);\n } else {\n await git.push([...args, remote]);\n }\n } catch (error) {\n throw new GitError('Failed to push', String(error));\n }\n};\n\nexport const pull = async (\n dir: string,\n options?: { remote?: string; branch?: string; rebase?: boolean }\n): Promise<void> => {\n try {\n const git = createGit(dir);\n const args: string[] = [];\n\n if (options?.rebase) {\n args.push('--rebase');\n }\n\n const remote = options?.remote || 'origin';\n const branch = options?.branch;\n\n if (branch) {\n await git.pull(remote, branch, args);\n } else {\n await git.pull(remote, undefined, args);\n }\n } catch (error) {\n throw new GitError('Failed to pull', String(error));\n }\n};\n\nexport const fetch = async (dir: string, remote = 'origin'): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.fetch(remote);\n } catch (error) {\n throw new GitError('Failed to fetch', String(error));\n }\n};\n\nexport const getLog = async (\n dir: string,\n options?: { maxCount?: number; since?: string }\n): Promise<GitCommit[]> => {\n try {\n const git = createGit(dir);\n const logOptions: { maxCount?: number; from?: string } = {\n maxCount: options?.maxCount || 10,\n };\n\n if (options?.since) {\n logOptions.from = options.since;\n }\n\n const log = await git.log(logOptions);\n\n return log.all.map((entry) => ({\n hash: entry.hash,\n date: entry.date,\n message: entry.message,\n author: entry.author_name || 'Unknown',\n }));\n } catch (error) {\n throw new GitError('Failed to get log', String(error));\n }\n};\n\nexport const getDiff = async (\n dir: string,\n options?: { staged?: boolean; stat?: boolean; files?: string[] }\n): Promise<string> => {\n try {\n const git = createGit(dir);\n const args: string[] = [];\n\n if (options?.staged) {\n args.push('--staged');\n }\n if (options?.stat) {\n args.push('--stat');\n }\n if (options?.files) {\n args.push('--');\n args.push(...options.files);\n }\n\n const result = await git.diff(args);\n return result;\n } catch (error) {\n throw new GitError('Failed to get diff', String(error));\n }\n};\n\nexport const getCurrentBranch = async (dir: string): Promise<string> => {\n try {\n const git = createGit(dir);\n const branch = await git.revparse(['--abbrev-ref', 'HEAD']);\n return branch.trim();\n } catch {\n // Fallback for repos with no commits - read symbolic-ref directly\n try {\n const git = createGit(dir);\n const ref = await git.raw(['symbolic-ref', '--short', 'HEAD']);\n return ref.trim();\n } catch {\n // Last resort - return default branch name\n return 'main';\n }\n }\n};\n\nexport const hasRemote = async (dir: string, name = 'origin'): Promise<boolean> => {\n try {\n const remotes = await getRemotes(dir);\n return remotes.some((r) => r.name === name);\n } catch {\n return false;\n }\n};\n\nexport const getRemoteUrl = async (dir: string, name = 'origin'): Promise<string | null> => {\n try {\n const remotes = await getRemotes(dir);\n const remote = remotes.find((r) => r.name === name);\n return remote?.url || null;\n } catch {\n return null;\n }\n};\n\nexport const setDefaultBranch = async (dir: string, branch: string): Promise<void> => {\n try {\n const git = createGit(dir);\n await git.branch(['-M', branch]);\n } catch (error) {\n throw new GitError('Failed to set default branch', String(error));\n }\n};\n","/**\n * Git Provider Abstraction Types\n *\n * This module defines the interface for git providers (GitHub, GitLab, etc.)\n * allowing tuck to work with multiple remote hosting services.\n */\n\n// ============================================================================\n// Provider Types\n// ============================================================================\n\n/** Supported provider modes */\nexport type ProviderMode = 'github' | 'gitlab' | 'local' | 'custom';\n\n/** User information from a provider */\nexport interface ProviderUser {\n /** Username/login identifier */\n login: string;\n /** Display name (may be null) */\n name: string | null;\n /** Email address (may be null) */\n email: string | null;\n}\n\n/** Repository information */\nexport interface ProviderRepo {\n /** Repository name (without owner) */\n name: string;\n /** Full name including owner (e.g., \"user/repo\") */\n fullName: string;\n /** Web URL for the repository */\n url: string;\n /** SSH clone URL */\n sshUrl: string;\n /** HTTPS clone URL */\n httpsUrl: string;\n /** Whether the repository is private */\n isPrivate: boolean;\n}\n\n/** Options for creating a new repository */\nexport interface CreateRepoOptions {\n /** Repository name */\n name: string;\n /** Repository description */\n description?: string;\n /** Whether to make the repository private (default: true) */\n isPrivate?: boolean;\n}\n\n/** Authentication status for a provider */\nexport interface AuthStatus {\n /** Whether the provider CLI is installed (if applicable) */\n cliInstalled: boolean;\n /** Whether the user is authenticated */\n authenticated: boolean;\n /** The authenticated user (if authenticated) */\n user?: ProviderUser;\n /** Provider-specific instance URL (for self-hosted) */\n instanceUrl?: string;\n}\n\n/** Detection result for a provider */\nexport interface ProviderDetection {\n /** Provider mode identifier */\n mode: ProviderMode;\n /** Human-readable provider name */\n displayName: string;\n /** Whether the provider is available (CLI installed, etc.) */\n available: boolean;\n /** Authentication status */\n authStatus: AuthStatus;\n /** Reason if not available */\n unavailableReason?: string;\n}\n\n// ============================================================================\n// Provider Interface\n// ============================================================================\n\n/**\n * Git Provider Interface\n *\n * Implementations of this interface provide a consistent API for\n * interacting with different git hosting services.\n */\nexport interface GitProvider {\n /** Provider mode identifier */\n readonly mode: ProviderMode;\n\n /** Human-readable provider name */\n readonly displayName: string;\n\n /** CLI command name (e.g., 'gh', 'glab') - null if no CLI */\n readonly cliName: string | null;\n\n /** Whether this provider requires a remote (local mode doesn't) */\n readonly requiresRemote: boolean;\n\n // -------------------------------------------------------------------------\n // Detection & Authentication\n // -------------------------------------------------------------------------\n\n /**\n * Check if the provider's CLI is installed\n * Returns true for providers without a CLI (local, custom)\n */\n isCliInstalled(): Promise<boolean>;\n\n /**\n * Check if the user is authenticated with the provider\n * Returns true for providers that don't require auth (local)\n */\n isAuthenticated(): Promise<boolean>;\n\n /**\n * Get the authenticated user's information\n * Returns null for providers without user accounts (local, custom)\n */\n getUser(): Promise<ProviderUser | null>;\n\n /**\n * Get full detection/authentication status\n */\n detect(): Promise<ProviderDetection>;\n\n // -------------------------------------------------------------------------\n // Repository Operations\n // -------------------------------------------------------------------------\n\n /**\n * Check if a repository exists\n * @param repoName Repository name or full name (owner/repo)\n */\n repoExists(repoName: string): Promise<boolean>;\n\n /**\n * Create a new repository\n * @param options Repository creation options\n * @returns The created repository info\n * @throws Error if creation fails or provider doesn't support creation\n */\n createRepo(options: CreateRepoOptions): Promise<ProviderRepo>;\n\n /**\n * Get information about a repository\n * @param repoName Repository name or full name\n */\n getRepoInfo(repoName: string): Promise<ProviderRepo | null>;\n\n /**\n * Clone a repository to a target directory\n * @param repoName Repository name or full name\n * @param targetDir Target directory path\n */\n cloneRepo(repoName: string, targetDir: string): Promise<void>;\n\n /**\n * Search for existing dotfiles repositories\n * @param username Optional username to search (defaults to authenticated user)\n * @returns Repository full name if found, null otherwise\n */\n findDotfilesRepo(username?: string): Promise<string | null>;\n\n // -------------------------------------------------------------------------\n // URL Utilities\n // -------------------------------------------------------------------------\n\n /**\n * Get the preferred clone URL for a repository\n * @param repo Repository info\n * @returns SSH or HTTPS URL based on user preference\n */\n getPreferredRepoUrl(repo: ProviderRepo): Promise<string>;\n\n /**\n * Validate a repository URL for this provider\n * @param url URL to validate\n * @returns true if the URL is valid for this provider\n */\n validateUrl(url: string): boolean;\n\n /**\n * Build a repository URL from components\n * @param username Owner/username\n * @param repoName Repository name\n * @param protocol SSH or HTTPS\n */\n buildRepoUrl(username: string, repoName: string, protocol: 'ssh' | 'https'): string;\n\n // -------------------------------------------------------------------------\n // Provider-specific Features\n // -------------------------------------------------------------------------\n\n /**\n * Get instructions for setting up this provider\n * Used when the provider isn't available or authenticated\n */\n getSetupInstructions(): string;\n\n /**\n * Get instructions for alternative authentication methods\n * (e.g., SSH keys, personal access tokens)\n */\n getAltAuthInstructions(): string;\n}\n\n// ============================================================================\n// Remote Configuration\n// ============================================================================\n\n/** Remote configuration stored in .tuckrc.json */\nexport interface RemoteConfig {\n /** Provider mode */\n mode: ProviderMode;\n /** Custom remote URL (for custom mode) */\n url?: string;\n /** Provider instance URL (for self-hosted GitLab, etc.) */\n providerUrl?: string;\n /** Cached username from provider */\n username?: string;\n /** Repository name */\n repoName?: string;\n}\n\n// ============================================================================\n// Provider Errors\n// ============================================================================\n\n/** Error thrown when a provider operation fails */\nexport class ProviderError extends Error {\n constructor(\n message: string,\n public readonly provider: ProviderMode,\n public readonly suggestions: string[] = []\n ) {\n super(message);\n this.name = 'ProviderError';\n }\n}\n\n/** Error thrown when provider is not configured */\nexport class ProviderNotConfiguredError extends ProviderError {\n constructor(provider: ProviderMode) {\n super(`Provider \"${provider}\" is not configured`, provider, [\n 'Run `tuck init` to set up your git provider',\n 'Or use `tuck config remote` to change providers',\n ]);\n this.name = 'ProviderNotConfiguredError';\n }\n}\n\n/** Error thrown when trying to use remote features in local mode */\nexport class LocalModeError extends ProviderError {\n constructor(operation: string) {\n super(`Cannot ${operation} in local-only mode`, 'local', [\n 'Your tuck is configured for local-only storage (no remote sync)',\n 'To enable remote sync, run: tuck config remote',\n 'Or re-run: tuck init',\n ]);\n this.name = 'LocalModeError';\n }\n}\n","/**\n * Input Validation Utilities\n *\n * Centralized validation functions with security-hardened checks.\n */\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nexport const GIT_OPERATION_TIMEOUTS = {\n LS_REMOTE: 30000, // 30 seconds (increased from 10s)\n CLONE: 300000, // 5 minutes\n FETCH: 60000, // 1 minute\n PUSH: 60000, // 1 minute\n} as const;\n\nconst BLOCKED_SYSTEM_PATHS = [\n '/etc/',\n '/proc/',\n '/sys/',\n '/dev/',\n '/boot/',\n '/root/',\n '/var/run/',\n '/var/log/',\n] as const;\n\nconst PRIVATE_IP_PATTERNS = [\n /^localhost$/i,\n /^127\\.\\d+\\.\\d+\\.\\d+$/,\n /^::1$/,\n /^0\\.0\\.0\\.0$/,\n /^10\\./,\n /^172\\.(1[6-9]|2\\d|3[01])\\./,\n /^192\\.168\\./,\n /^169\\.254\\./, // Link-local\n /^fe80:/i, // IPv6 link-local\n] as const;\n\n// ============================================================================\n// Repository Name Validation\n// ============================================================================\n\n/**\n * Validate repository name with strict security checks\n * @param repoName Repository name to validate\n * @param provider Provider name for error messages\n * @throws Error if validation fails\n */\nexport function validateRepoName(repoName: string, provider: string): void {\n // Check for control characters and null bytes\n // eslint-disable-next-line no-control-regex\n if (/[\\x00-\\x1F\\x7F]/.test(repoName)) {\n throw new Error('Repository name contains invalid control characters');\n }\n\n // Handle full URLs\n if (repoName.includes('://')) {\n validateHttpUrl(repoName, provider);\n return;\n }\n\n if (repoName.startsWith('git@')) {\n validateSshUrl(repoName, provider);\n return;\n }\n\n // For owner/repo or repo format, validate strictly\n const validPattern = /^[a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?(?:\\/[a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?)*$/;\n if (!validPattern.test(repoName)) {\n throw new Error(\n 'Repository names must start and end with alphanumeric characters and can only contain alphanumeric characters, hyphens, underscores, and dots. Format: \"owner/repo\" or \"repo\"'\n );\n }\n}\n\n/**\n * Validate HTTP(S) URL\n */\nfunction validateHttpUrl(url: string, provider: string): void {\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(url);\n } catch {\n throw new Error(`Invalid repository URL: ${url}`);\n }\n\n // Restrict to common git-related protocols\n const allowedProtocols = new Set(['http:', 'https:', 'ssh:', 'git+ssh:']);\n if (!allowedProtocols.has(parsedUrl.protocol)) {\n throw new Error(`Invalid protocol in URL. Allowed: ${Array.from(allowedProtocols).join(', ')}`);\n }\n\n // Validate hostname\n if (!/^[a-zA-Z0-9.-]+$/.test(parsedUrl.hostname)) {\n throw new Error('Invalid characters in hostname');\n }\n\n // Check for shell metacharacters\n if (/[;&|`$(){}[\\]<>!#*?'\"\\\\]/.test(url)) {\n throw new Error('URL contains invalid characters');\n }\n\n // Path validation for known providers\n if (provider === 'github' && parsedUrl.hostname === 'github.com') {\n const pathPattern = /^\\/[a-zA-Z0-9._-]+\\/[a-zA-Z0-9._-]+(?:\\.git)?$/;\n if (!pathPattern.test(parsedUrl.pathname)) {\n throw new Error('Invalid GitHub repository URL format. Expected: /owner/repo or /owner/repo.git');\n }\n }\n}\n\n/**\n * Validate SSH URL (git@host:path format)\n */\nfunction validateSshUrl(url: string, _provider: string): void {\n // Check for shell metacharacters before pattern matching\n if (/[;&|`$(){}[\\]<>!#*?'\"\\\\]/.test(url)) {\n throw new Error('URL contains invalid characters');\n }\n\n // Pattern for git@host:path format\n const sshPattern = /^git@([a-zA-Z0-9.-]+):([a-zA-Z0-9._/-]+)(?:\\.git)?$/;\n if (!sshPattern.test(url)) {\n throw new Error('Invalid SSH URL format. Expected: git@host:path or git@host:path.git');\n }\n\n const match = url.match(sshPattern);\n if (match) {\n const [, host, path] = match;\n\n // Validate host\n if (!/^[a-zA-Z0-9.-]+$/.test(host)) {\n throw new Error('Invalid hostname in SSH URL');\n }\n\n // Validate path doesn't contain suspicious patterns\n if (path.includes('..')) {\n throw new Error('Path traversal not allowed in repository URL');\n }\n }\n}\n\n// ============================================================================\n// Repository Description Validation\n// ============================================================================\n\n/**\n * Validate repository description with length and character limits\n * @param description Description to validate\n * @param maxLength Maximum length (default: 350 for GitHub)\n */\nexport function validateDescription(description: string, maxLength: number = 350): void {\n // Length check\n if (description.length > maxLength) {\n throw new Error(`Description too long (max ${maxLength} characters)`);\n }\n\n // Check for invalid characters including quotes, newlines, and shell metacharacters\n // eslint-disable-next-line no-control-regex\n if (/[;&|`$(){}[\\]<>!#*?'\"\\\\n\\r\\t\\x00-\\x1F\\x7F]/.test(description)) {\n throw new Error(\n 'Description contains invalid characters. Cannot contain: ; & | ` $ ( ) { } [ ] < > ! # * ? \\' \" \\\\ newlines or control characters'\n );\n }\n\n // Normalize unicode to prevent homograph attacks\n const normalized = description.normalize('NFKC');\n if (normalized !== description) {\n throw new Error('Description contains unusual Unicode characters');\n }\n}\n\n// ============================================================================\n// Hostname Validation (for self-hosted GitLab)\n// ============================================================================\n\n/**\n * Validate hostname for self-hosted instances with SSRF protection\n * @param hostname Hostname to validate\n * @throws Error if validation fails\n */\nexport function validateHostname(hostname: string): void {\n if (!hostname) {\n throw new Error('Hostname is required');\n }\n\n // Length check\n if (hostname.length > 253) {\n throw new Error('Hostname too long (max 253 characters)');\n }\n\n // Strict hostname validation with TLD requirement\n // Pattern: label.label.tld where labels are alphanumeric with hyphens (not at start/end)\n const hostnamePattern = /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$/;\n if (!hostnamePattern.test(hostname)) {\n throw new Error(\n 'Invalid hostname format. Must be a fully qualified domain name (e.g., gitlab.example.com)'\n );\n }\n\n // Block localhost and loopback addresses\n for (const pattern of PRIVATE_IP_PATTERNS) {\n if (pattern.test(hostname)) {\n throw new Error('Private IP addresses and localhost are not allowed for security reasons');\n }\n }\n\n // Additional check: reject hostnames that are just TLDs or single labels\n const labels = hostname.split('.');\n if (labels.length < 2) {\n throw new Error('Hostname must have at least two labels (subdomain.domain.tld)');\n }\n}\n\n// ============================================================================\n// Git URL Validation\n// ============================================================================\n\n/**\n * Validate git URL with comprehensive security checks\n */\nexport function validateGitUrl(url: string): boolean {\n // Check for control characters\n // eslint-disable-next-line no-control-regex\n if (/[\\x00-\\x1F\\x7F]/.test(url)) {\n return false;\n }\n\n // SSH format: git@host:path.git or git@host:path\n const sshPattern = /^git@[a-zA-Z0-9.-]+:[a-zA-Z0-9._/-]+(?:\\.git)?$/;\n\n // SSH URL format: ssh://git@host/path\n const sshUrlPattern = /^ssh:\\/\\/git@[a-zA-Z0-9.-]+\\/[a-zA-Z0-9._/-]+(?:\\.git)?$/;\n\n // HTTPS format: https://host/path.git or https://host/path\n const httpsPattern = /^https?:\\/\\/[a-zA-Z0-9.-]+\\/[a-zA-Z0-9._/-]+(?:\\.git)?$/;\n\n // Git protocol: git://host/path\n const gitPattern = /^git:\\/\\/[a-zA-Z0-9.-]+\\/[a-zA-Z0-9._/-]+(?:\\.git)?$/;\n\n // File path (local): /path/to/repo or file:///path/to/repo\n if (url.startsWith('file://') || url.startsWith('/')) {\n return validateFileUrl(url);\n }\n\n // Check if it matches any valid pattern\n if (\n sshPattern.test(url) ||\n sshUrlPattern.test(url) ||\n httpsPattern.test(url) ||\n gitPattern.test(url)\n ) {\n // Additional check: no shell metacharacters\n if (/[;&|`$(){}[\\]<>!#*?]/.test(url.replace(/[/:@.]/g, ''))) {\n return false;\n }\n return true;\n }\n\n return false;\n}\n\n/**\n * Validate file:// URL with path traversal and sensitive path protection\n */\nfunction validateFileUrl(url: string): boolean {\n // Extract path\n const path = url.replace(/^file:\\/\\//, '');\n\n // Block sensitive system paths\n for (const blockedPath of BLOCKED_SYSTEM_PATHS) {\n if (path.startsWith(blockedPath)) {\n return false;\n }\n }\n\n // Block path traversal\n if (path.includes('../') || path.includes('/..')) {\n return false;\n }\n\n // Require absolute paths\n if (!path.startsWith('/')) {\n return false;\n }\n\n // Basic path pattern\n const filePattern = /^\\/[a-zA-Z0-9._/-]+$/;\n return filePattern.test(path);\n}\n\n// ============================================================================\n// Error Message Sanitization\n// ============================================================================\n\n/**\n * Sanitize error messages to prevent information disclosure\n * @param error Error object or string\n * @param genericMessage Generic message to show to users\n * @returns Sanitized error message\n */\nexport function sanitizeErrorMessage(error: unknown, genericMessage: string): string {\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n\n // Detect common error types and provide appropriate messages\n if (message.includes('enotfound') || message.includes('network')) {\n return 'Network error. Please check your internet connection.';\n }\n if (message.includes('permission') || message.includes('eacces')) {\n return 'Permission denied. Please check your access rights.';\n }\n if (message.includes('timeout') || message.includes('etimedout')) {\n return 'Operation timed out. Please try again.';\n }\n if (message.includes('authentication') || message.includes('auth')) {\n return 'Authentication failed. Please check your credentials.';\n }\n\n // For other errors, use generic message\n return genericMessage;\n }\n\n return genericMessage;\n}\n","/**\n * GitLab Provider Implementation\n *\n * Provides GitLab integration via the `glab` CLI tool.\n * Supports both gitlab.com and self-hosted instances.\n */\n\nimport { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport type {\n GitProvider,\n ProviderUser,\n ProviderRepo,\n CreateRepoOptions,\n ProviderDetection,\n} from './types.js';\nimport { ProviderError } from './types.js';\nimport {\n validateRepoName as validateRepoNameUtil,\n validateDescription as validateDescriptionUtil,\n sanitizeErrorMessage,\n} from '../validation.js';\n\nconst execFileAsync = promisify(execFile);\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst COMMON_DOTFILE_REPO_NAMES = ['dotfiles', 'tuck', '.dotfiles', 'dot-files', 'dots'];\nconst DEFAULT_GITLAB_HOST = 'gitlab.com';\n\n// ============================================================================\n// GitLab Provider\n// ============================================================================\n\nexport class GitLabProvider implements GitProvider {\n readonly mode = 'gitlab' as const;\n readonly displayName = 'GitLab';\n readonly cliName = 'glab';\n readonly requiresRemote = true;\n\n /** The GitLab host (gitlab.com or self-hosted URL) */\n private host: string;\n\n constructor(host: string = DEFAULT_GITLAB_HOST) {\n // Normalize host - remove protocol if present\n this.host = host.replace(/^https?:\\/\\//, '').replace(/\\/$/, '');\n }\n\n /** Create a provider for a specific host */\n static forHost(host: string): GitLabProvider {\n return new GitLabProvider(host);\n }\n\n // -------------------------------------------------------------------------\n // Detection & Authentication\n // -------------------------------------------------------------------------\n\n async isCliInstalled(): Promise<boolean> {\n try {\n await execFileAsync('glab', ['--version']);\n return true;\n } catch {\n return false;\n }\n }\n\n async isAuthenticated(): Promise<boolean> {\n try {\n const { stdout, stderr } = await execFileAsync('glab', ['auth', 'status', '-h', this.host]);\n const output = (stderr || stdout || '').trim();\n // glab outputs \"Logged in to <host> as <username>\" on success\n return output.includes('Logged in');\n } catch (error) {\n if (error instanceof Error && 'stderr' in error) {\n const stderr = (error as { stderr: string }).stderr;\n return stderr.includes('Logged in');\n }\n return false;\n }\n }\n\n async getUser(): Promise<ProviderUser | null> {\n if (!(await this.isCliInstalled()) || !(await this.isAuthenticated())) {\n return null;\n }\n\n try {\n // glab api returns user info\n const { stdout } = await execFileAsync('glab', ['api', 'user', '-h', this.host]);\n const data = JSON.parse(stdout);\n return {\n login: data.username || '',\n name: data.name || null,\n email: data.email || null,\n };\n } catch (error) {\n // Primary API call failed - try fallback method\n // This is expected if user doesn't have API access\n try {\n const { stdout, stderr } = await execFileAsync('glab', ['auth', 'status', '-h', this.host]);\n const output = stderr || stdout || '';\n // Parse \"Logged in to gitlab.com as username\" format\n const match = output.match(/Logged in to .+ as (\\S+)/);\n if (match) {\n return {\n login: match[1],\n name: null,\n email: null,\n };\n }\n } catch (fallbackError) {\n // Both methods failed - gracefully return null\n // This allows the application to continue with limited user info\n }\n return null;\n }\n }\n\n async detect(): Promise<ProviderDetection> {\n const cliInstalled = await this.isCliInstalled();\n\n if (!cliInstalled) {\n return {\n mode: this.mode,\n displayName: this.getDisplayNameWithHost(),\n available: false,\n authStatus: {\n cliInstalled: false,\n authenticated: false,\n instanceUrl: this.getInstanceUrl(),\n },\n unavailableReason: 'GitLab CLI (glab) is not installed',\n };\n }\n\n const authenticated = await this.isAuthenticated();\n const user = authenticated ? await this.getUser() : undefined;\n\n return {\n mode: this.mode,\n displayName: this.getDisplayNameWithHost(),\n available: authenticated,\n authStatus: {\n cliInstalled: true,\n authenticated,\n user: user || undefined,\n instanceUrl: this.getInstanceUrl(),\n },\n unavailableReason: !authenticated ? `Not logged in to GitLab (${this.host})` : undefined,\n };\n }\n\n // -------------------------------------------------------------------------\n // Repository Operations\n // -------------------------------------------------------------------------\n\n async repoExists(repoName: string): Promise<boolean> {\n this.validateRepoName(repoName);\n try {\n await execFileAsync('glab', ['repo', 'view', repoName, '-h', this.host]);\n return true;\n } catch {\n return false;\n }\n }\n\n async createRepo(options: CreateRepoOptions): Promise<ProviderRepo> {\n if (!(await this.isCliInstalled())) {\n throw new ProviderError('GitLab CLI is not installed', 'gitlab', [\n 'Install with: brew install glab (macOS)',\n 'Or see: https://gitlab.com/gitlab-org/cli',\n ]);\n }\n\n if (!(await this.isAuthenticated())) {\n throw new ProviderError(`Not authenticated with GitLab (${this.host})`, 'gitlab', [\n `Run: glab auth login -h ${this.host}`,\n ]);\n }\n\n const user = await this.getUser();\n if (!user) {\n throw new ProviderError('Could not get GitLab user information', 'gitlab');\n }\n\n // Validate inputs BEFORE checking if repo exists (to fail fast)\n this.validateRepoName(options.name);\n\n // Validate description if provided (improved validation)\n if (options.description) {\n try {\n validateDescriptionUtil(options.description, 2000); // GitLab allows 2000 chars\n } catch (error) {\n throw new ProviderError(\n error instanceof Error ? error.message : 'Invalid description',\n 'gitlab'\n );\n }\n }\n\n const fullName = `${user.login}/${options.name}`;\n\n if (await this.repoExists(fullName)) {\n throw new ProviderError(`Repository \"${fullName}\" already exists`, 'gitlab', [\n `Use a different name or import the existing repo`,\n ]);\n }\n\n const args: string[] = ['repo', 'create', options.name, '-h', this.host];\n\n // GitLab uses --private and --public flags\n if (options.isPrivate !== false) {\n args.push('--private');\n } else {\n args.push('--public');\n }\n\n if (options.description) {\n args.push('--description', options.description);\n }\n\n // Add --confirm to skip prompts (glab calls it -y or --yes)\n args.push('-y');\n\n try {\n const { stdout } = await execFileAsync('glab', args);\n\n // Parse the output to get repo info\n // glab outputs the URL of the created repo\n const urlMatch = stdout.match(/https?:\\/\\/[^\\s]+/);\n const repoUrl = urlMatch ? urlMatch[0] : `https://${this.host}/${fullName}`;\n\n return {\n name: options.name,\n fullName,\n url: repoUrl,\n sshUrl: `git@${this.host}:${fullName}.git`,\n httpsUrl: `https://${this.host}/${fullName}.git`,\n isPrivate: options.isPrivate !== false,\n };\n } catch (error) {\n // Sanitize error message to prevent information disclosure\n const sanitizedMessage = sanitizeErrorMessage(error, 'Failed to create repository');\n throw new ProviderError(sanitizedMessage, 'gitlab', [\n `Try creating the repository manually at https://${this.host}/projects/new`,\n ]);\n }\n }\n\n async getRepoInfo(repoName: string): Promise<ProviderRepo | null> {\n this.validateRepoName(repoName);\n try {\n const { stdout } = await execFileAsync('glab', [\n 'repo',\n 'view',\n repoName,\n '-h',\n this.host,\n '-o',\n 'json',\n ]);\n const result = JSON.parse(stdout);\n\n const pathWithNamespace = result.path_with_namespace || repoName;\n\n return {\n name: result.name || repoName.split('/').pop() || repoName,\n fullName: pathWithNamespace,\n url: result.web_url || `https://${this.host}/${pathWithNamespace}`,\n sshUrl: result.ssh_url_to_repo || `git@${this.host}:${pathWithNamespace}.git`,\n httpsUrl: result.http_url_to_repo || `https://${this.host}/${pathWithNamespace}.git`,\n isPrivate: result.visibility === 'private',\n };\n } catch {\n return null;\n }\n }\n\n async cloneRepo(repoName: string, targetDir: string): Promise<void> {\n if (!(await this.isCliInstalled())) {\n throw new ProviderError('GitLab CLI is not installed', 'gitlab');\n }\n\n this.validateRepoName(repoName);\n\n try {\n await execFileAsync('glab', ['repo', 'clone', repoName, targetDir, '-h', this.host]);\n } catch (error) {\n throw new ProviderError(`Failed to clone repository \"${repoName}\"`, 'gitlab', [\n String(error),\n 'Check that the repository exists and you have access',\n ]);\n }\n }\n\n async findDotfilesRepo(username?: string): Promise<string | null> {\n const user = username || (await this.getUser())?.login;\n if (!user) return null;\n\n for (const name of COMMON_DOTFILE_REPO_NAMES) {\n const repoName = `${user}/${name}`;\n if (await this.repoExists(repoName)) {\n return repoName;\n }\n }\n\n return null;\n }\n\n // -------------------------------------------------------------------------\n // URL Utilities\n // -------------------------------------------------------------------------\n\n async getPreferredRepoUrl(repo: ProviderRepo): Promise<string> {\n const protocol = await this.getPreferredProtocol();\n return protocol === 'ssh' ? repo.sshUrl : repo.httpsUrl;\n }\n\n validateUrl(url: string): boolean {\n const host = this.host.replace(/\\./g, '\\\\.');\n const httpsPattern = new RegExp(`^https://${host}/`);\n const sshPattern = new RegExp(`^git@${host}:`);\n const sshUrlPattern = new RegExp(`^ssh://git@${host}/`);\n\n return httpsPattern.test(url) || sshPattern.test(url) || sshUrlPattern.test(url);\n }\n\n buildRepoUrl(username: string, repoName: string, protocol: 'ssh' | 'https'): string {\n if (protocol === 'ssh') {\n return `git@${this.host}:${username}/${repoName}.git`;\n }\n return `https://${this.host}/${username}/${repoName}.git`;\n }\n\n // -------------------------------------------------------------------------\n // Instructions\n // -------------------------------------------------------------------------\n\n getSetupInstructions(): string {\n const { platform } = process;\n\n let installCmd = '';\n if (platform === 'darwin') {\n installCmd = 'brew install glab';\n } else if (platform === 'linux') {\n installCmd = `# Debian/Ubuntu:\n# Download from https://gitlab.com/gitlab-org/cli/-/releases\n\n# Or using brew:\nbrew install glab`;\n } else if (platform === 'win32') {\n installCmd = `# Using winget:\nwinget install GitLab.glab\n\n# Using scoop:\nscoop install glab`;\n }\n\n const hostInstructions =\n this.host !== DEFAULT_GITLAB_HOST\n ? `\nFor self-hosted GitLab (${this.host}):\nglab auth login -h ${this.host}`\n : '';\n\n return `GitLab CLI (glab) - Official GitLab command line tool\n\nInstallation:\n${installCmd}\n\nAfter installing, authenticate:\nglab auth login\n${hostInstructions}\n\nBenefits:\n- Automatic repository creation\n- No manual token management\n- Works with self-hosted GitLab\n\nLearn more: https://gitlab.com/gitlab-org/cli`;\n }\n\n getAltAuthInstructions(): string {\n return `Alternative authentication methods for GitLab:\n\n1. SSH Keys (recommended if glab CLI unavailable)\n - Generate: ssh-keygen -t ed25519\n - Add to GitLab: https://${this.host}/-/user_settings/ssh_keys\n - Test: ssh -T git@${this.host}\n\n2. Personal Access Token\n - Create at: https://${this.host}/-/user_settings/personal_access_tokens\n - Required scopes: \"api\", \"read_repository\", \"write_repository\"\n - Use as password when pushing\n\nFor detailed instructions, see:\nhttps://docs.gitlab.com/ee/user/ssh.html`;\n }\n\n // -------------------------------------------------------------------------\n // Private Helpers\n // -------------------------------------------------------------------------\n\n private validateRepoName(repoName: string): void {\n try {\n validateRepoNameUtil(repoName, 'gitlab');\n } catch (error) {\n throw new ProviderError(\n error instanceof Error ? error.message : 'Invalid repository name',\n 'gitlab'\n );\n }\n }\n\n private async getPreferredProtocol(): Promise<'ssh' | 'https'> {\n try {\n const { stdout } = await execFileAsync('glab', [\n 'config',\n 'get',\n 'git_protocol',\n '-h',\n this.host,\n ]);\n return stdout.trim().toLowerCase() === 'ssh' ? 'ssh' : 'https';\n } catch {\n return 'https';\n }\n }\n\n private getDisplayNameWithHost(): string {\n if (this.host === DEFAULT_GITLAB_HOST) {\n return 'GitLab';\n }\n return `GitLab (${this.host})`;\n }\n\n private getInstanceUrl(): string {\n return `https://${this.host}`;\n }\n}\n\n// Export default instance for gitlab.com\nexport const gitlabProvider = new GitLabProvider();\n","import { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport { GitHubCliError } from '../errors.js';\n\nconst execFileAsync = promisify(execFile);\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** API request timeout in milliseconds (10 seconds) */\nconst API_REQUEST_TIMEOUT_MS = 10000;\n\n/**\n * Git credential helper fallback cache timeout in seconds (24 hours).\n * This is used when the git credential helper falls back to cache mode on Linux.\n */\nconst GIT_CREDENTIAL_CACHE_FALLBACK_TIMEOUT_SECONDS = 86400;\n\n/** Days threshold for warning about potentially expired tokens (85 days, before typical 90-day expiration) */\nconst TOKEN_EXPIRATION_WARNING_DAYS = 85;\n\n/** Minimum length for a valid GitHub token */\nexport const MIN_GITHUB_TOKEN_LENGTH = 20;\n\n/**\n * Valid GitHub token prefixes for validation purposes.\n * Note: detectTokenType() only distinguishes between fine-grained (github_pat_)\n * and classic (ghp_) tokens, but GitHub issues other token types that should\n * still be accepted as valid (gho_, ghu_, ghs_, ghr_).\n */\nexport const GITHUB_TOKEN_PREFIXES = [\n 'github_pat_', // Fine-grained PAT\n 'ghp_', // Classic PAT\n 'gho_', // OAuth token\n 'ghu_', // User token\n 'ghs_', // Server token\n 'ghr_', // Refresh token\n] as const;\n\n/**\n * Validate repository name/identifier to prevent command injection.\n * Valid formats: \"owner/repo\", \"repo\", or full URLs\n */\nconst validateRepoName = (repoName: string): void => {\n // Allow full URLs (https:// or git@)\n if (repoName.includes('://') || repoName.startsWith('git@')) {\n // Basic URL validation - must not contain shell metacharacters\n if (/[;&|`$(){}[\\]<>!#*?]/.test(repoName.replace(/[/:@.]/g, ''))) {\n throw new GitHubCliError(`Invalid repository URL: ${repoName}`);\n }\n return;\n }\n\n // For owner/repo or repo format, validate strictly\n // Valid: alphanumeric, hyphens, underscores, dots, and single forward slash\n const validPattern = /^[a-zA-Z0-9._-]+(?:\\/[a-zA-Z0-9._-]+)?$/;\n if (!validPattern.test(repoName)) {\n throw new GitHubCliError(`Invalid repository name: ${repoName}`, [\n 'Repository names can only contain alphanumeric characters, hyphens, underscores, and dots',\n 'Format: \"owner/repo\" or \"repo\"',\n ]);\n }\n};\n\nexport interface GitHubUser {\n login: string;\n name: string | null;\n email: string | null;\n}\n\nexport interface GitHubRepo {\n name: string;\n fullName: string;\n url: string;\n sshUrl: string;\n httpsUrl: string;\n isPrivate: boolean;\n}\n\nexport interface CreateRepoOptions {\n name: string;\n description?: string;\n isPrivate?: boolean;\n homepage?: string;\n}\n\n/**\n * Check if the GitHub CLI (gh) is installed\n */\nexport const isGhInstalled = async (): Promise<boolean> => {\n try {\n await execFileAsync('gh', ['--version']);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Check if the user is authenticated with GitHub CLI\n */\nexport const isGhAuthenticated = async (): Promise<boolean> => {\n try {\n // gh auth status outputs to stderr, not stdout\n // execFileAsync provides both stdout and stderr even on success\n const { stdout, stderr } = await execFileAsync('gh', ['auth', 'status']);\n // Check stderr (where gh auth status outputs) and stdout (as fallback)\n const output = (stderr || stdout || '').trim();\n // Only return true if we can definitively confirm authentication\n // Check for positive indicator, not absence of negative indicator\n return output.includes('Logged in');\n } catch (error) {\n // gh auth status returns exit code 1 when not authenticated\n // and outputs error message to stderr\n if (error instanceof Error && 'stderr' in error) {\n const stderr = (error as { stderr: string }).stderr;\n // Only return true if stderr explicitly confirms authentication\n return stderr.includes('Logged in');\n }\n return false;\n }\n};\n\n/**\n * Get the authenticated GitHub user's information\n */\nexport const getAuthenticatedUser = async (): Promise<GitHubUser> => {\n if (!(await isGhInstalled())) {\n throw new GitHubCliError('GitHub CLI is not installed');\n }\n\n if (!(await isGhAuthenticated())) {\n throw new GitHubCliError('Not authenticated with GitHub CLI', [\n 'Run `gh auth login` to authenticate',\n ]);\n }\n\n try {\n const { stdout } = await execFileAsync('gh', ['api', 'user', '--jq', '.login, .name, .email']);\n const lines = stdout.trim().split('\\n');\n return {\n login: lines[0] || '',\n name: lines[1] !== 'null' ? lines[1] : null,\n email: lines[2] !== 'null' ? lines[2] : null,\n };\n } catch (error) {\n throw new GitHubCliError('Failed to get user information', [\n String(error),\n 'Check your GitHub CLI authentication',\n ]);\n }\n};\n\n/**\n * Check if a repository exists on GitHub\n */\nexport const repoExists = async (repoName: string): Promise<boolean> => {\n try {\n validateRepoName(repoName);\n await execFileAsync('gh', ['repo', 'view', repoName, '--json', 'name']);\n return true;\n } catch {\n return false;\n }\n};\n\ninterface RepoCreationDiagnosis {\n reason: string;\n suggestions: string[];\n}\n\n/**\n * Diagnose why repository creation failed and provide helpful suggestions\n */\nconst diagnoseRepoCreationFailure = async (\n repoName: string,\n errorMessage: string\n): Promise<RepoCreationDiagnosis> => {\n const errorLower = errorMessage.toLowerCase();\n\n // Check if repo already exists (double-check in case of race condition)\n try {\n const user = await getAuthenticatedUser();\n const fullName = `${user.login}/${repoName}`;\n if (await repoExists(fullName)) {\n return {\n reason: `Repository \"${fullName}\" already exists`,\n suggestions: [\n `Use the existing repository: tuck init --from ${fullName}`,\n `Delete it first at github.com/${fullName}/settings`,\n 'Choose a different name for your dotfiles repository',\n ],\n };\n }\n } catch {\n // Ignore - continue with other checks\n }\n\n // Permission errors\n if (errorLower.includes('permission') || errorLower.includes('forbidden') || errorLower.includes('403')) {\n return {\n reason: 'Insufficient permissions to create repository',\n suggestions: [\n 'Check your GitHub CLI authentication: gh auth status',\n 'Re-authenticate with repo scope: gh auth login --scopes repo',\n 'Create the repository manually at github.com/new',\n ],\n };\n }\n\n // Name already taken (in an org or different context)\n if (errorLower.includes('name already exists') || errorLower.includes('already exists')) {\n return {\n reason: `Repository name \"${repoName}\" is already taken`,\n suggestions: [\n 'Choose a different name (e.g., \"my-dotfiles\", \"dotfiles-backup\")',\n 'Check if you already have this repository: gh repo list',\n 'Create the repository manually at github.com/new',\n ],\n };\n }\n\n // Rate limiting\n if (errorLower.includes('rate limit') || errorLower.includes('429') || errorLower.includes('too many')) {\n return {\n reason: 'GitHub API rate limit exceeded',\n suggestions: [\n 'Wait a few minutes and try again',\n 'Create the repository manually at github.com/new',\n ],\n };\n }\n\n // Network issues\n if (\n errorLower.includes('network') ||\n errorLower.includes('enotfound') ||\n errorLower.includes('timeout') ||\n errorLower.includes('econnrefused')\n ) {\n return {\n reason: 'Network error - could not reach GitHub',\n suggestions: [\n 'Check your internet connection',\n 'Try again in a moment',\n 'Create the repository manually at github.com/new',\n ],\n };\n }\n\n // Authentication expired or invalid\n if (errorLower.includes('401') || errorLower.includes('unauthorized') || errorLower.includes('bad credentials')) {\n return {\n reason: 'GitHub authentication expired or invalid',\n suggestions: [\n 'Re-authenticate: gh auth login',\n 'Check your token: gh auth status',\n ],\n };\n }\n\n // Generic fallback with manual instructions\n return {\n reason: `Failed to create repository \"${repoName}\"`,\n suggestions: [\n 'Create the repository manually:',\n ' 1. Go to github.com/new',\n ` 2. Name: ${repoName}`,\n ' 3. Visibility: Private (recommended)',\n ' 4. Do NOT initialize with README/.gitignore',\n ' 5. Click \"Create repository\"',\n ' 6. Copy the URL and paste when prompted',\n ],\n };\n};\n\n/**\n * Create a new GitHub repository\n */\nexport const createRepo = async (options: CreateRepoOptions): Promise<GitHubRepo> => {\n if (!(await isGhInstalled())) {\n throw new GitHubCliError('GitHub CLI is not installed');\n }\n\n if (!(await isGhAuthenticated())) {\n throw new GitHubCliError('Not authenticated with GitHub CLI', [\n 'Run `gh auth login` to authenticate',\n ]);\n }\n\n // Check if repo already exists\n const user = await getAuthenticatedUser();\n const fullName = `${user.login}/${options.name}`;\n\n if (await repoExists(fullName)) {\n throw new GitHubCliError(`Repository \"${fullName}\" already exists`, [\n `Use a different name or run \\`tuck init --remote ${fullName}\\``,\n ]);\n }\n\n // Validate inputs to prevent command injection\n validateRepoName(options.name);\n \n if (options.description && /[;&|`$(){}[\\]<>!#*?]/.test(options.description)) {\n throw new GitHubCliError('Invalid description: contains unsafe characters');\n }\n \n if (options.homepage && /[;&|`$(){}[\\]<>!#*?]/.test(options.homepage)) {\n throw new GitHubCliError('Invalid homepage: contains unsafe characters');\n }\n\n try {\n // Build command arguments array to prevent command injection\n const args: string[] = ['repo', 'create', options.name];\n \n if (options.isPrivate !== false) {\n args.push('--private');\n } else {\n args.push('--public');\n }\n \n if (options.description) {\n args.push('--description', options.description);\n }\n \n if (options.homepage) {\n args.push('--homepage', options.homepage);\n }\n \n args.push('--confirm', '--json', 'name,url,sshUrl');\n \n const { stdout } = await execFileAsync('gh', args);\n const result = JSON.parse(stdout);\n\n return {\n name: result.name,\n fullName: `${user.login}/${result.name}`,\n url: result.url,\n sshUrl: result.sshUrl,\n httpsUrl: result.url.replace('github.com', 'github.com').replace(/^https?:\\/\\//, 'https://'),\n isPrivate: options.isPrivate !== false,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const diagnosis = await diagnoseRepoCreationFailure(options.name, errorMessage);\n throw new GitHubCliError(diagnosis.reason, diagnosis.suggestions);\n }\n};\n\n/**\n * Get the preferred remote URL format (SSH or HTTPS)\n */\nexport const getPreferredRemoteProtocol = async (): Promise<'ssh' | 'https'> => {\n try {\n const { stdout } = await execFileAsync('gh', ['config', 'get', 'git_protocol']);\n const protocol = stdout.trim().toLowerCase();\n return protocol === 'ssh' ? 'ssh' : 'https';\n } catch {\n // Default to HTTPS if we can't determine preference\n return 'https';\n }\n};\n\n/**\n * Get repository information from GitHub\n */\nexport const getRepoInfo = async (repoName: string): Promise<GitHubRepo | null> => {\n try {\n validateRepoName(repoName);\n const { stdout } = await execFileAsync('gh', [\n 'repo',\n 'view',\n repoName,\n '--json',\n 'name,url,sshUrl,isPrivate,owner',\n ]);\n const result = JSON.parse(stdout);\n\n return {\n name: result.name,\n fullName: `${result.owner.login}/${result.name}`,\n url: result.url,\n sshUrl: result.sshUrl,\n httpsUrl: result.url,\n isPrivate: result.isPrivate,\n };\n } catch {\n return null;\n }\n};\n\n/**\n * Clone a repository to a specific directory using gh CLI\n */\nexport const ghCloneRepo = async (repoName: string, targetDir: string): Promise<void> => {\n if (!(await isGhInstalled())) {\n throw new GitHubCliError('GitHub CLI is not installed');\n }\n\n validateRepoName(repoName);\n\n try {\n await execFileAsync('gh', ['repo', 'clone', repoName, targetDir]);\n } catch (error) {\n throw new GitHubCliError(`Failed to clone repository \"${repoName}\"`, [\n String(error),\n 'Check that the repository exists and you have access',\n ]);\n }\n};\n\n/**\n * Find a user's dotfiles repository (checks common names)\n */\nexport const findDotfilesRepo = async (username?: string): Promise<string | null> => {\n const user = username || (await getAuthenticatedUser()).login;\n const commonNames = ['dotfiles', 'tuck', '.dotfiles', 'dot-files', 'dots'];\n\n for (const name of commonNames) {\n const repoName = `${user}/${name}`;\n if (await repoExists(repoName)) {\n return repoName;\n }\n }\n\n return null;\n};\n\n/**\n * Get the remote URL in the user's preferred format (SSH or HTTPS)\n */\nexport const getPreferredRepoUrl = async (repo: GitHubRepo): Promise<string> => {\n const protocol = await getPreferredRemoteProtocol();\n return protocol === 'ssh' ? repo.sshUrl : repo.httpsUrl;\n};\n\n// ============================================================================\n// Alternative Authentication Methods (when GitHub CLI is not available)\n// ============================================================================\n\nexport interface SSHKeyInfo {\n exists: boolean;\n path: string;\n publicKeyPath: string;\n publicKey?: string;\n}\n\n/**\n * Check if SSH keys exist for GitHub\n */\nexport const checkSSHKeys = async (): Promise<SSHKeyInfo> => {\n const { homedir } = await import('os');\n const { join } = await import('path');\n const { readFile } = await import('fs/promises');\n const { pathExists } = await import('./paths.js');\n\n const sshDir = join(homedir(), '.ssh');\n const keyTypes = ['id_ed25519', 'id_rsa', 'id_ecdsa'];\n\n for (const keyType of keyTypes) {\n const privateKeyPath = join(sshDir, keyType);\n const publicKeyPath = `${privateKeyPath}.pub`;\n\n if (await pathExists(publicKeyPath)) {\n try {\n const publicKey = await readFile(publicKeyPath, 'utf-8');\n return {\n exists: true,\n path: privateKeyPath,\n publicKeyPath,\n publicKey: publicKey.trim(),\n };\n } catch {\n return {\n exists: true,\n path: privateKeyPath,\n publicKeyPath,\n };\n }\n }\n }\n\n return {\n exists: false,\n path: join(sshDir, 'id_ed25519'),\n publicKeyPath: join(sshDir, 'id_ed25519.pub'),\n };\n};\n\n/**\n * Determine the appropriate StrictHostKeyChecking option for GitHub SSH tests.\n * Uses \"yes\" if github.com is already in known_hosts, otherwise \"accept-new\".\n */\nconst getStrictHostKeyCheckingOption = async (): Promise<string> => {\n try {\n const { homedir } = await import('os');\n const { join } = await import('path');\n const { readFile } = await import('fs/promises');\n\n const sshDir = join(homedir(), '.ssh');\n const knownHostsPath = join(sshDir, 'known_hosts');\n\n const knownHostsContent = await readFile(knownHostsPath, 'utf-8');\n\n // Check if github.com already has a plain-text entry by looking for lines that start with 'github.com'\n // Note: We don't check hashed entries (|1|...) because we can't verify the hostname without\n // attempting the SSH connection. For security purposes, we only trust explicit github.com entries.\n // Format: \"github.com[,port] key-type key-data [comment]\" or \"@marker github.com[,port] key-type...\"\n const hasGitHubEntry = knownHostsContent.split('\\n').some(line => {\n const trimmed = line.trim();\n // Skip comments and empty lines\n if (!trimmed || trimmed.startsWith('#')) return false;\n \n // Handle @marker entries (e.g., @cert-authority or @revoked)\n const hostnamePart = trimmed.startsWith('@') \n ? trimmed.split(/\\s+/)[1] // Get second field after marker\n : trimmed.split(/\\s+/)[0]; // Get first field for regular entries\n \n // Check for exact hostname match (github.com or github.com,port)\n if (!hostnamePart) return false;\n return hostnamePart === 'github.com' || hostnamePart.startsWith('github.com,');\n });\n\n if (hasGitHubEntry) {\n return 'yes';\n }\n } catch {\n // If known_hosts doesn't exist or can't be read, fall back to accept-new\n // to preserve existing behavior for first-time setups.\n }\n\n // Use accept-new for better UX on first connection. This will automatically\n // trust a new host key, which can weaken protection against MITM attacks during\n // initial key establishment. However, since the target is hard-coded to github.com,\n // whose SSH host keys are well-known and documented, the practical risk is low.\n return 'accept-new';\n};\n\n/**\n * Test if SSH connection to GitHub works\n */\nexport const testSSHConnection = async (): Promise<{ success: boolean; username?: string }> => {\n try {\n const strictHostKeyChecking = await getStrictHostKeyCheckingOption();\n // ssh -T git@github.com returns exit code 1 even on success, but outputs the username\n const { stderr } = await execFileAsync('ssh', ['-T', '-o', `StrictHostKeyChecking=${strictHostKeyChecking}`, 'git@github.com']);\n const match = stderr.match(/Hi ([^!]+)!/);\n if (match) {\n return { success: true, username: match[1] };\n }\n return { success: false };\n } catch (error) {\n // SSH returns exit code 1 even on successful auth, check stderr for success message\n if (error instanceof Error && 'stderr' in error) {\n const stderr = (error as { stderr: string }).stderr;\n const match = stderr.match(/Hi ([^!]+)!/);\n if (match) {\n return { success: true, username: match[1] };\n }\n }\n return { success: false };\n }\n};\n\n/**\n * Get instructions for generating SSH keys\n */\nexport const getSSHKeyInstructions = (email?: string): string => {\n const emailFlag = email ? ` -C \"${email}\"` : '';\n\n return `\nTo set up SSH authentication with GitHub:\n\n1. Generate a new SSH key (recommended: Ed25519):\n ssh-keygen -t ed25519${emailFlag}\n\n Press Enter to accept the default file location\n Enter a passphrase (recommended) or press Enter for none\n\n2. Start the SSH agent:\n eval \"$(ssh-agent -s)\"\n\n3. Add your SSH key to the agent:\n ssh-add ~/.ssh/id_ed25519\n\n4. Copy your public key:\n - macOS: pbcopy < ~/.ssh/id_ed25519.pub\n - Linux: cat ~/.ssh/id_ed25519.pub\n\n5. Add the key to GitHub:\n - Go to: https://github.com/settings/ssh/new\n - Title: Your computer name (e.g., \"MacBook Pro\")\n - Key type: Authentication Key\n - Key: Paste your public key\n - Click \"Add SSH key\"\n\n6. Test the connection:\n ssh -T git@github.com\n\n You should see: \"Hi username! You've successfully authenticated...\"\n`.trim();\n};\n\n/**\n * Get instructions for creating a fine-grained personal access token\n */\nexport const getFineGrainedTokenInstructions = (repoName?: string): string => {\n return `\nTo create a Fine-grained Personal Access Token (recommended):\n\n1. Go to: https://github.com/settings/tokens?type=beta\n\n2. Click \"Generate new token\"\n\n3. Configure the token:\n - Token name: \"tuck-dotfiles\" (or any descriptive name)\n - Expiration: 90 days (or custom, can be renewed)\n - Description: \"Token for tuck dotfiles manager\"\n\n4. Repository access:\n - Select \"Only select repositories\"\n - Choose your dotfiles repository${repoName ? ` (${repoName})` : ''}\n - Or select \"All repositories\" if you haven't created it yet\n\n5. Permissions needed (under \"Repository permissions\"):\n ┌─────────────────────────┬─────────────────┐\n │ Permission │ Access Level │\n ├─────────────────────────┼─────────────────┤\n │ Contents │ Read and write │\n │ Metadata │ Read-only │\n └─────────────────────────┴─────────────────┘\n\n That's it! Only 2 permissions needed.\n\n6. Click \"Generate token\"\n\n7. IMPORTANT: Copy the token immediately!\n It won't be shown again.\n\n8. Configure git to use the token:\n When pushing, use this as your password:\n - Username: your-github-username\n - Password: github_pat_xxxxxxxxxxxx (your token)\n\n Or configure credential storage:\n git config --global credential.helper store\n\n Then on first push, enter your token as the password\n and it will be saved for future use.\n`.trim();\n};\n\n/**\n * Get instructions for creating a classic personal access token\n */\nexport const getClassicTokenInstructions = (): string => {\n return `\nTo create a Classic Personal Access Token:\n\nNote: Fine-grained tokens are recommended for better security,\nbut classic tokens work if you need broader access.\n\n1. Go to: https://github.com/settings/tokens/new\n\n2. Configure the token:\n - Note: \"tuck-dotfiles\" (or any descriptive name)\n - Expiration: 90 days (or \"No expiration\" - less secure)\n\n3. Select scopes (permissions):\n ┌─────────────────────────┬─────────────────────────────────────┐\n │ Scope │ Why it's needed │\n ├─────────────────────────┼─────────────────────────────────────┤\n │ ☑ repo │ Full access to private repositories │\n │ ☑ repo:status │ Access commit status │\n │ ☑ repo_deployment │ Access deployment status │\n │ ☑ public_repo │ Access public repositories │\n │ ☑ repo:invite │ Access repository invitations │\n └─────────────────────────┴─────────────────────────────────────┘\n\n Just check the top-level \"repo\" box - it selects all sub-items.\n\n4. Click \"Generate token\"\n\n5. IMPORTANT: Copy the token immediately!\n It starts with \"ghp_\" and won't be shown again.\n\n6. Configure git to use the token:\n When pushing, use this as your password:\n - Username: your-github-username\n - Password: ghp_xxxxxxxxxxxx (your token)\n\n Or configure credential storage:\n git config --global credential.helper store\n\n Then on first push, enter your token as the password.\n`.trim();\n};\n\n/**\n * Get instructions for installing GitHub CLI\n */\nexport const getGitHubCLIInstallInstructions = (): string => {\n const { platform } = process;\n\n let installCmd = '';\n if (platform === 'darwin') {\n installCmd = 'brew install gh';\n } else if (platform === 'linux') {\n installCmd = `# Debian/Ubuntu:\nsudo apt install gh\n\n# Fedora:\nsudo dnf install gh\n\n# Arch Linux:\nsudo pacman -S github-cli`;\n } else if (platform === 'win32') {\n installCmd = `# Using winget:\nwinget install GitHub.cli\n\n# Using scoop:\nscoop install gh\n\n# Using chocolatey:\nchoco install gh`;\n }\n\n return `\nGitHub CLI (gh) - Recommended for the best experience\n\nThe GitHub CLI provides the easiest authentication and\nlets tuck automatically create repositories for you.\n\nInstallation:\n${installCmd}\n\nAfter installing, authenticate:\ngh auth login\n\nBenefits:\n- Automatic repository creation\n- No manual token management\n- Easy authentication refresh\n- Works with SSH or HTTPS\n\nLearn more: https://cli.github.com/\n`.trim();\n};\n\nexport type AuthMethod = 'gh-cli' | 'ssh' | 'fine-grained-token' | 'classic-token';\n\nexport interface AuthMethodInfo {\n id: AuthMethod;\n name: string;\n description: string;\n recommended: boolean;\n instructions: string;\n}\n\n/**\n * Get all available authentication methods with instructions\n */\nexport const getAuthMethods = (repoName?: string, email?: string): AuthMethodInfo[] => {\n return [\n {\n id: 'gh-cli',\n name: 'GitHub CLI (gh)',\n description: 'Easiest option - automatic repo creation, no token management',\n recommended: true,\n instructions: getGitHubCLIInstallInstructions(),\n },\n {\n id: 'ssh',\n name: 'SSH Key',\n description: 'Secure, no password needed after setup, works everywhere',\n recommended: false,\n instructions: getSSHKeyInstructions(email),\n },\n {\n id: 'fine-grained-token',\n name: 'Fine-grained Token',\n description: 'Limited permissions, more secure, repository-specific',\n recommended: false,\n instructions: getFineGrainedTokenInstructions(repoName),\n },\n {\n id: 'classic-token',\n name: 'Classic Token',\n description: 'Broader access, simpler setup, works with all repos',\n recommended: false,\n instructions: getClassicTokenInstructions(),\n },\n ];\n};\n\n/**\n * Configure git credential helper for HTTPS authentication\n */\nexport const configureGitCredentialHelper = async (): Promise<void> => {\n const { platform } = process;\n\n // Check if a credential helper is already configured\n try {\n const { stdout } = await execFileAsync('git', ['config', '--global', 'credential.helper']);\n if (stdout.trim()) {\n // User already has a credential helper configured, don't override it\n return;\n }\n } catch {\n // No credential helper configured, proceed with setup\n }\n\n try {\n if (platform === 'darwin') {\n // macOS - use Keychain\n await execFileAsync('git', ['config', '--global', 'credential.helper', 'osxkeychain']);\n } else if (platform === 'linux') {\n // Linux - use libsecret if available, otherwise cache\n try {\n await execFileAsync('git', ['config', '--global', 'credential.helper', 'libsecret']);\n } catch (error) {\n console.info(\n 'git-credential-libsecret is not available; falling back to git credential cache helper with timeout of ' +\n `${GIT_CREDENTIAL_CACHE_FALLBACK_TIMEOUT_SECONDS} seconds.`\n );\n await execFileAsync('git', ['config', '--global', 'credential.helper', `cache --timeout=${GIT_CREDENTIAL_CACHE_FALLBACK_TIMEOUT_SECONDS}`]);\n }\n } else if (platform === 'win32') {\n // Windows - use credential manager\n await execFileAsync('git', ['config', '--global', 'credential.helper', 'manager']);\n }\n } catch {\n // Fallback to store (less secure but works everywhere)\n await execFileAsync('git', ['config', '--global', 'credential.helper', 'store']);\n }\n};\n\n// ============================================================================\n// Secure Credential Management\n// ============================================================================\n\nexport interface StoredCredential {\n username: string;\n token: string;\n createdAt: string;\n type: 'fine-grained' | 'classic';\n}\n\n/**\n * Get the path to the tuck credentials file\n */\nconst getCredentialsPath = async (): Promise<string> => {\n const { homedir } = await import('os');\n const { join } = await import('path');\n return join(homedir(), '.tuck', '.credentials.json');\n};\n\n/**\n * Store GitHub credentials securely\n * Uses git credential helper for the actual token storage\n * Stores metadata (type, creation date) in tuck config\n */\nexport const storeGitHubCredentials = async (\n username: string,\n token: string,\n type: 'fine-grained' | 'classic'\n): Promise<void> => {\n const { writeFile, mkdir } = await import('fs/promises');\n const { dirname } = await import('path');\n\n // First, configure the credential helper\n await configureGitCredentialHelper();\n\n // Validate that username and token do not contain newline characters,\n // which would break the git credential helper protocol format.\n if (/[\\r\\n]/.test(username) || /[\\r\\n]/.test(token)) {\n throw new GitHubCliError('Username or token contains invalid newline characters.', [\n \"Newline characters are not allowed in GitHub usernames or tokens because git's credential helper protocol is line-based.\",\n 'Each credential field is sent as \"key=value\" on its own line; embedded newlines would corrupt this format and cause git credential storage to fail.',\n 'If you copied the token from a password manager or web page, ensure it is a single line with no trailing line breaks, then paste it again or regenerate a new token.',\n ]);\n }\n\n // Store the credential using git credential helper\n // This pipes the credential to git credential approve\n const credentialInput = `protocol=https\\nhost=github.com\\nusername=${username}\\npassword=${token}\\n\\n`; // Note: git credential protocol requires input to be terminated with a blank line (\\n\\n)\n\n try {\n const { spawn } = await import('child_process');\n await new Promise<void>((resolve, reject) => {\n const proc = spawn('git', ['credential', 'approve'], {\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n proc.stdin.write(credentialInput);\n proc.stdin.end();\n\n proc.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error('git credential approve failed'));\n }\n });\n\n proc.on('error', reject);\n });\n } catch (error) {\n // If git credential helper fails, we can still continue.\n // The user will just be prompted for credentials on push.\n const warningMessage =\n 'Failed to store GitHub credentials via `git credential approve`. ' +\n 'Credentials will not be cached and you may be prompted again on push.';\n\n // Emit a process warning so this is visible in a non-blocking way.\n try {\n process.emitWarning(warningMessage, {\n code: 'GIT_CREDENTIAL_HELPER_FAILED',\n });\n } catch {\n // Fallback: emitting a warning should never break the main flow.\n }\n\n // Also log to console for environments that rely on standard output logging.\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n console.warn(`Warning: ${warningMessage} Error: ${errorMessage}`);\n }\n\n // Store metadata (not the token itself) for expiration tracking\n const credentialsPath = await getCredentialsPath();\n const metadata = {\n username,\n type,\n createdAt: new Date().toISOString(),\n // Don't store the actual token - just track that we have one\n hasToken: true,\n };\n\n try {\n await mkdir(dirname(credentialsPath), { recursive: true });\n // Note: File permissions (0o600) protect this metadata file on the filesystem,\n // but the username stored in this file is in plaintext and may be readable by\n // any process running as the same OS user. Only non-secret metadata such as\n // the username and token presence/creation time are stored here; the actual\n // token is stored securely via the git credential helper (e.g., osxkeychain,\n // libsecret, manager) which uses OS-level secure storage. The security of the\n // token itself depends on the credential helper implementation, not this file.\n await writeFile(credentialsPath, JSON.stringify(metadata, null, 2), {\n mode: 0o600, // Read/write only for owner\n });\n } catch (error) {\n // Non-critical - metadata storage failed, but surface a warning as this affects\n // security-relevant file permissions/metadata and token expiration tracking.\n const warningMessage =\n `Failed to store GitHub credential metadata at \"${credentialsPath}\". ` +\n 'Token expiration tracking and verification of restricted file permissions ' +\n '(0o600) may not work as expected.';\n\n // Emit a process warning so this is visible to the user in a non-blocking way.\n try {\n process.emitWarning(warningMessage, {\n code: 'GITHUB_CREDENTIAL_METADATA_WRITE_FAILED',\n });\n } catch {\n // Fallback: emitting a warning should never break the main flow.\n }\n\n // Also log to console for environments that rely on standard output logging,\n // but avoid exposing full filesystem paths by default. Detailed information,\n // including the credential metadata path and underlying error, is only logged\n // when an explicit debug flag is enabled.\n const isDebugLoggingEnabled =\n process.env.GITHUB_DEBUG_CREDENTIALS_METADATA === '1';\n if (isDebugLoggingEnabled) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n console.warn(\n `Warning: ${warningMessage} Error: ${errorMessage}`,\n );\n } else {\n console.warn(\n 'Warning: Failed to store GitHub credential metadata. ' +\n 'Token expiration tracking and verification of restricted file ' +\n 'permissions (0o600) may not work as expected.',\n );\n }\n }\n};\n\n/**\n * Get stored credential metadata\n */\nexport const getStoredCredentialMetadata = async (): Promise<{\n username?: string;\n type?: 'fine-grained' | 'classic';\n createdAt?: Date;\n hasToken?: boolean;\n} | null> => {\n const { readFile } = await import('fs/promises');\n const { pathExists } = await import('./paths.js');\n\n const credentialsPath = await getCredentialsPath();\n\n if (!(await pathExists(credentialsPath))) {\n return null;\n }\n\n try {\n const content = await readFile(credentialsPath, 'utf-8');\n const data = JSON.parse(content);\n return {\n username: data.username,\n type: data.type,\n createdAt: data.createdAt ? new Date(data.createdAt) : undefined,\n hasToken: data.hasToken,\n };\n } catch {\n return null;\n }\n};\n\n/**\n * Remove stored credentials (both from git helper and metadata)\n */\nexport const removeStoredCredentials = async (): Promise<void> => {\n const { unlink } = await import('fs/promises');\n const { pathExists } = await import('./paths.js');\n\n // Remove from git credential helper\n try {\n const { spawn } = await import('child_process');\n await new Promise<void>((resolve) => {\n const proc = spawn('git', ['credential', 'reject'], {\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n // Note: git credential protocol requires input to be terminated with a blank line (\\n\\n)\n proc.stdin.write('protocol=https\\nhost=github.com\\n\\n');\n proc.stdin.end();\n\n proc.on('close', () => resolve());\n proc.on('error', () => resolve());\n });\n } catch {\n // Ignore errors\n }\n\n // Remove metadata file\n const credentialsPath = await getCredentialsPath();\n if (await pathExists(credentialsPath)) {\n try {\n await unlink(credentialsPath);\n } catch {\n // Ignore errors\n }\n }\n};\n\n/**\n * Test if stored credentials are still valid\n * Uses GitHub API /user endpoint which requires authentication\n */\nexport const testStoredCredentials = async (): Promise<{\n valid: boolean;\n reason?: 'expired' | 'invalid' | 'network' | 'unknown';\n username?: string;\n}> => {\n const metadata = await getStoredCredentialMetadata();\n\n if (!metadata?.hasToken) {\n return { valid: false, reason: 'unknown' };\n }\n\n // Get credentials from git credential helper\n let username: string | null = null;\n let password: string | null = null;\n\n try {\n const { spawn } = await import('child_process');\n const credentialOutput = await new Promise<string>((resolve, reject) => {\n const proc = spawn('git', ['credential', 'fill'], {\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n // Request credentials for github.com\n proc.stdin.write('protocol=https\\nhost=github.com\\n\\n');\n proc.stdin.end();\n\n let output = '';\n proc.stdout.on('data', (data) => {\n output += data.toString();\n });\n\n proc.on('close', (code) => {\n if (code === 0) {\n resolve(output);\n } else {\n reject(new Error('git credential fill failed'));\n }\n });\n\n proc.on('error', reject);\n });\n\n // Parse credential output (format: key=value\\n). Values may contain '=' characters,\n // so split into at most two parts: key and the full remaining value.\n for (const line of credentialOutput.trim().split('\\n')) {\n const [key, value] = line.split('=', 2);\n if (value === undefined) {\n continue;\n }\n if (key === 'username') {\n username = value;\n } else if (key === 'password') {\n password = value;\n }\n }\n } catch {\n // If we can't get credentials, they're not valid\n return { valid: false, reason: 'unknown', username: metadata.username };\n }\n\n if (!username || !password) {\n return { valid: false, reason: 'unknown', username: metadata.username };\n }\n\n // Test credentials against GitHub API /user endpoint (requires authentication)\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), API_REQUEST_TIMEOUT_MS);\n\n // Prefer Bearer token auth when the \"password\" looks like a GitHub token,\n // but fall back to Basic auth for traditional username/password credentials.\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github+json',\n 'User-Agent': 'tuck-dotfiles-manager',\n };\n\n const looksLikeToken =\n typeof password === 'string' &&\n password.length >= MIN_GITHUB_TOKEN_LENGTH &&\n GITHUB_TOKEN_PREFIXES.some((prefix) => password.startsWith(prefix));\n\n if (looksLikeToken) {\n headers.Authorization = `Bearer ${password}`;\n } else {\n const auth = Buffer.from(`${username}:${password}`).toString('base64');\n headers.Authorization = `Basic ${auth}`;\n }\n\n try {\n const response = await fetch('https://api.github.com/user', {\n method: 'GET',\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // 200 OK means credentials are valid\n if (response.status === 200) {\n try {\n // Parse user data to extract username (in case it differs from metadata)\n const userData = (await response.json()) as { login?: string };\n const apiUsername = userData.login || username;\n return { valid: true, username: apiUsername };\n } catch {\n // Even if we can't parse, 200 OK means auth succeeded\n // Use username from credentials if valid, otherwise fall back to metadata username\n const effectiveUsername = (username && username.trim()) || metadata.username;\n return { valid: true, username: effectiveUsername };\n }\n }\n\n // 401 Unauthorized means invalid credentials\n if (response.status === 401) {\n // Check if token might be expired based on creation date\n if (metadata.createdAt) {\n const daysSinceCreation = Math.floor(\n (Date.now() - metadata.createdAt.getTime()) / (1000 * 60 * 60 * 24)\n );\n\n // Fine-grained tokens often expire in 90 days, classic can vary\n if (daysSinceCreation > TOKEN_EXPIRATION_WARNING_DAYS) {\n return { valid: false, reason: 'expired', username: metadata.username };\n }\n }\n return { valid: false, reason: 'invalid', username: metadata.username };\n }\n\n // 403 Forbidden could mean token is invalid or lacks permissions\n if (response.status === 403) {\n return { valid: false, reason: 'invalid', username: metadata.username };\n }\n\n // Other status codes are unexpected\n return { valid: false, reason: 'unknown', username: metadata.username };\n } catch (fetchError) {\n clearTimeout(timeoutId);\n throw fetchError;\n }\n } catch (error) {\n const errorStr = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n\n // Check for timeout/abort errors\n if (errorStr.includes('aborted') || errorStr.includes('timeout')) {\n return { valid: false, reason: 'network', username: metadata.username };\n }\n\n // Check for network-related errors\n if (\n errorStr.includes('network') ||\n errorStr.includes('enotfound') ||\n errorStr.includes('econnrefused') ||\n errorStr.includes('could not resolve') ||\n errorStr.includes('fetch failed') ||\n errorStr.includes('getaddrinfo')\n ) {\n return { valid: false, reason: 'network', username: metadata.username };\n }\n\n return { valid: false, reason: 'unknown', username: metadata.username };\n }\n};\n\n/**\n * Diagnose authentication issues and provide helpful suggestions\n */\nexport const diagnoseAuthIssue = async (): Promise<{\n issue: string;\n suggestions: string[];\n}> => {\n const metadata = await getStoredCredentialMetadata();\n\n if (!metadata?.hasToken) {\n return {\n issue: 'No GitHub credentials configured',\n suggestions: [\n 'Set up authentication using one of the methods below',\n 'Run `tuck init` to configure GitHub access',\n ],\n };\n }\n\n const testResult = await testStoredCredentials();\n\n if (testResult.valid) {\n return {\n issue: 'Credentials appear to be working',\n suggestions: ['Try the operation again'],\n };\n }\n\n switch (testResult.reason) {\n case 'expired':\n return {\n issue: `Your ${metadata.type || 'GitHub'} token has likely expired`,\n suggestions: [\n metadata.type === 'fine-grained'\n ? 'Create a new fine-grained token at: https://github.com/settings/tokens?type=beta'\n : 'Create a new token at: https://github.com/settings/tokens/new',\n 'Use the same permissions as before',\n 'Run `tuck init` to update your credentials',\n ],\n };\n\n case 'invalid':\n return {\n issue: 'Your GitHub credentials are invalid',\n suggestions: [\n 'The token may have been revoked or is incorrect',\n 'Check your tokens at: https://github.com/settings/tokens',\n 'Create a new token and run `tuck init` to update',\n ],\n };\n\n case 'network':\n return {\n issue: 'Could not connect to GitHub',\n suggestions: [\n 'Check your internet connection',\n 'GitHub may be experiencing issues - check https://githubstatus.com',\n 'Try again in a moment',\n ],\n };\n\n default:\n return {\n issue: 'Unknown authentication issue',\n suggestions: [\n 'Try creating a new token',\n 'Check https://github.com/settings/tokens for your existing tokens',\n 'Run `tuck init` to reconfigure authentication',\n ],\n };\n }\n};\n\n/**\n * Update stored credentials with a new token\n */\nexport const updateStoredCredentials = async (\n token: string,\n type?: 'fine-grained' | 'classic'\n): Promise<void> => {\n const metadata = await getStoredCredentialMetadata();\n const username = metadata?.username;\n\n if (!username) {\n throw new Error(\n 'GitHub credential metadata is incomplete or corrupted (missing username). ' +\n 'Please remove the credential file and re-authenticate by running `tuck config` or `tuck init`.'\n );\n }\n\n // Determine token type, preferring explicit type, then stored metadata, then detection\n const detectedType = detectTokenType(token);\n const tokenType = type ?? metadata?.type ?? detectedType;\n\n // Ensure we have a valid token type (not 'unknown')\n if (tokenType !== 'fine-grained' && tokenType !== 'classic') {\n throw new Error(\n 'Could not determine GitHub token type. The token format is not recognized. ' +\n 'Please verify your token starts with \"github_pat_\" (fine-grained) or \"ghp_\" (classic), ' +\n 'or generate a new token at https://github.com/settings/tokens'\n );\n }\n\n // Remove old credentials first\n await removeStoredCredentials();\n\n // Store new credentials\n await storeGitHubCredentials(username, token, tokenType);\n};\n\n/**\n * Detect token type from the token format\n */\nexport const detectTokenType = (token: string): 'fine-grained' | 'classic' | 'unknown' => {\n // Fine-grained tokens start with github_pat_\n if (token.startsWith('github_pat_')) {\n return 'fine-grained';\n }\n // Classic tokens start with ghp_\n if (token.startsWith('ghp_')) {\n return 'classic';\n }\n return 'unknown';\n};\n","import { join, basename, isAbsolute } from 'path';\nimport { readdir, stat } from 'fs/promises';\nimport { platform } from 'os';\nimport { pathExists, expandPath, collapsePath } from './paths.js';\n\nconst IS_MACOS = platform() === 'darwin';\nconst IS_LINUX = platform() === 'linux';\n\nexport interface DetectedFile {\n path: string;\n name: string;\n category: string;\n description: string;\n isDirectory: boolean;\n size?: number;\n sensitive?: boolean;\n exclude?: string[]; // Patterns to exclude within directories\n}\n\nexport interface DetectionCategory {\n name: string;\n icon: string;\n description: string;\n}\n\nexport const DETECTION_CATEGORIES: Record<string, DetectionCategory> = {\n shell: {\n name: 'Shell',\n icon: '$',\n description: 'Shell configs, aliases, functions, and environment',\n },\n git: {\n name: 'Git',\n icon: '*',\n description: 'Git settings, aliases, and global ignores',\n },\n editors: {\n name: 'Editors',\n icon: '>',\n description: 'Editor configurations and settings',\n },\n terminal: {\n name: 'Terminal',\n icon: '#',\n description: 'Terminal emulators and tmux/screen',\n },\n prompt: {\n name: 'Prompt & Theme',\n icon: '~',\n description: 'Shell prompts, themes, and color schemes',\n },\n cli: {\n name: 'CLI Tools',\n icon: '%',\n description: 'Command-line tool configurations',\n },\n languages: {\n name: 'Languages',\n icon: '@',\n description: 'Programming language and package manager configs',\n },\n ssh: {\n name: 'SSH & Security',\n icon: '!',\n description: 'SSH config and GPG settings (no private keys)',\n },\n xdg: {\n name: 'XDG Apps',\n icon: '.',\n description: 'Applications using ~/.config standard',\n },\n desktop: {\n name: 'Desktop & WM',\n icon: '+',\n description: 'Window managers and desktop environment configs',\n },\n scripts: {\n name: 'Scripts',\n icon: '/',\n description: 'Custom scripts and local binaries',\n },\n macos: {\n name: 'macOS',\n icon: '^',\n description: 'macOS-specific configurations',\n },\n misc: {\n name: 'Other',\n icon: '-',\n description: 'Other configuration files',\n },\n};\n\n/**\n * Comprehensive list of dotfiles to detect\n */\nconst DOTFILE_PATTERNS: Array<{\n path: string;\n category: string;\n description: string;\n sensitive?: boolean;\n exclude?: string[];\n platform?: 'darwin' | 'linux' | 'all';\n}> = [\n // ==================== SHELL CONFIGURATION ====================\n // Bash\n { path: '~/.bashrc', category: 'shell', description: 'Bash interactive shell config' },\n { path: '~/.bash_profile', category: 'shell', description: 'Bash login shell config' },\n { path: '~/.bash_aliases', category: 'shell', description: 'Bash aliases' },\n { path: '~/.bash_functions', category: 'shell', description: 'Bash functions' },\n { path: '~/.bash_logout', category: 'shell', description: 'Bash logout script' },\n\n // Zsh\n { path: '~/.zshrc', category: 'shell', description: 'Zsh interactive shell config' },\n { path: '~/.zprofile', category: 'shell', description: 'Zsh login shell config' },\n { path: '~/.zshenv', category: 'shell', description: 'Zsh environment variables' },\n { path: '~/.zlogin', category: 'shell', description: 'Zsh login script' },\n { path: '~/.zlogout', category: 'shell', description: 'Zsh logout script' },\n { path: '~/.zsh', category: 'shell', description: 'Zsh configuration directory' },\n\n // Fish\n { path: '~/.config/fish/config.fish', category: 'shell', description: 'Fish shell config' },\n { path: '~/.config/fish/functions', category: 'shell', description: 'Fish functions' },\n { path: '~/.config/fish/completions', category: 'shell', description: 'Fish completions' },\n { path: '~/.config/fish/conf.d', category: 'shell', description: 'Fish config snippets' },\n\n // Generic shell\n { path: '~/.profile', category: 'shell', description: 'Generic shell profile' },\n { path: '~/.aliases', category: 'shell', description: 'Shell aliases' },\n { path: '~/.functions', category: 'shell', description: 'Shell functions' },\n { path: '~/.exports', category: 'shell', description: 'Environment exports' },\n { path: '~/.inputrc', category: 'shell', description: 'Readline configuration' },\n { path: '~/.hushlogin', category: 'shell', description: 'Suppress login message' },\n\n // ==================== GIT CONFIGURATION ====================\n { path: '~/.gitconfig', category: 'git', description: 'Git global configuration' },\n { path: '~/.gitignore_global', category: 'git', description: 'Global gitignore patterns' },\n { path: '~/.gitignore', category: 'git', description: 'Global gitignore (alt location)' },\n { path: '~/.gitmessage', category: 'git', description: 'Git commit message template' },\n { path: '~/.gitattributes', category: 'git', description: 'Git attributes' },\n { path: '~/.config/git/config', category: 'git', description: 'Git XDG config' },\n { path: '~/.config/git/ignore', category: 'git', description: 'Git XDG ignore' },\n { path: '~/.config/gh', category: 'git', description: 'GitHub CLI config' },\n { path: '~/.config/hub', category: 'git', description: 'Hub CLI config' },\n\n // ==================== EDITORS & IDES ====================\n // Vim/Neovim\n { path: '~/.vimrc', category: 'editors', description: 'Vim configuration' },\n { path: '~/.vim', category: 'editors', description: 'Vim directory', exclude: ['plugged', 'bundle', '.netrwhist'] },\n { path: '~/.config/nvim', category: 'editors', description: 'Neovim configuration' },\n { path: '~/.ideavimrc', category: 'editors', description: 'IdeaVim (JetBrains) config' },\n\n // Emacs\n { path: '~/.emacs', category: 'editors', description: 'Emacs configuration' },\n { path: '~/.emacs.d/init.el', category: 'editors', description: 'Emacs init file' },\n { path: '~/.doom.d', category: 'editors', description: 'Doom Emacs config' },\n { path: '~/.spacemacs', category: 'editors', description: 'Spacemacs config' },\n\n // VS Code\n { path: '~/.config/Code/User/settings.json', category: 'editors', description: 'VS Code settings', platform: 'linux' },\n { path: '~/.config/Code/User/keybindings.json', category: 'editors', description: 'VS Code keybindings', platform: 'linux' },\n { path: '~/.config/Code/User/snippets', category: 'editors', description: 'VS Code snippets', platform: 'linux' },\n { path: '~/Library/Application Support/Code/User/settings.json', category: 'editors', description: 'VS Code settings', platform: 'darwin' },\n { path: '~/Library/Application Support/Code/User/keybindings.json', category: 'editors', description: 'VS Code keybindings', platform: 'darwin' },\n { path: '~/Library/Application Support/Code/User/snippets', category: 'editors', description: 'VS Code snippets', platform: 'darwin' },\n\n // Cursor (VS Code fork)\n { path: '~/.config/Cursor/User/settings.json', category: 'editors', description: 'Cursor settings', platform: 'linux' },\n { path: '~/Library/Application Support/Cursor/User/settings.json', category: 'editors', description: 'Cursor settings', platform: 'darwin' },\n\n // Other editors\n { path: '~/.nanorc', category: 'editors', description: 'Nano configuration' },\n { path: '~/.config/micro', category: 'editors', description: 'Micro editor config' },\n { path: '~/.config/helix', category: 'editors', description: 'Helix editor config' },\n { path: '~/.sublime-text/Packages/User', category: 'editors', description: 'Sublime Text settings' },\n\n // ==================== TERMINAL & MULTIPLEXERS ====================\n // Tmux\n { path: '~/.tmux.conf', category: 'terminal', description: 'Tmux configuration' },\n { path: '~/.tmux', category: 'terminal', description: 'Tmux directory' },\n { path: '~/.config/tmux/tmux.conf', category: 'terminal', description: 'Tmux XDG config' },\n\n // Screen\n { path: '~/.screenrc', category: 'terminal', description: 'GNU Screen configuration' },\n\n // Terminal emulators\n { path: '~/.config/alacritty', category: 'terminal', description: 'Alacritty terminal config' },\n { path: '~/.config/kitty', category: 'terminal', description: 'Kitty terminal config' },\n { path: '~/.config/wezterm', category: 'terminal', description: 'WezTerm config' },\n { path: '~/.wezterm.lua', category: 'terminal', description: 'WezTerm config (alt)' },\n { path: '~/.config/hyper', category: 'terminal', description: 'Hyper terminal config' },\n { path: '~/.hyper.js', category: 'terminal', description: 'Hyper terminal config (alt)' },\n { path: '~/.config/foot', category: 'terminal', description: 'Foot terminal config' },\n { path: '~/.config/terminator', category: 'terminal', description: 'Terminator config' },\n { path: '~/.config/tilix', category: 'terminal', description: 'Tilix terminal config' },\n { path: '~/Library/Preferences/com.googlecode.iterm2.plist', category: 'terminal', description: 'iTerm2 preferences', platform: 'darwin' },\n\n // ==================== PROMPT & THEMES ====================\n { path: '~/.config/starship.toml', category: 'prompt', description: 'Starship prompt config' },\n { path: '~/.p10k.zsh', category: 'prompt', description: 'Powerlevel10k config' },\n { path: '~/.oh-my-zsh/custom', category: 'prompt', description: 'Oh My Zsh customizations' },\n { path: '~/.config/powerline', category: 'prompt', description: 'Powerline config' },\n { path: '~/.dir_colors', category: 'prompt', description: 'Directory colors' },\n { path: '~/.dircolors', category: 'prompt', description: 'Directory colors (alt)' },\n\n // ==================== CLI TOOLS ====================\n // Search & navigation\n { path: '~/.config/ripgrep', category: 'cli', description: 'Ripgrep config' },\n { path: '~/.ripgreprc', category: 'cli', description: 'Ripgrep config (alt)' },\n { path: '~/.rgrc', category: 'cli', description: 'Ripgrep config (short)' },\n { path: '~/.config/fd', category: 'cli', description: 'fd find config' },\n { path: '~/.fdignore', category: 'cli', description: 'fd ignore patterns' },\n { path: '~/.config/bat', category: 'cli', description: 'bat (better cat) config' },\n { path: '~/.config/lsd', category: 'cli', description: 'lsd (better ls) config' },\n { path: '~/.config/exa', category: 'cli', description: 'exa config' },\n { path: '~/.config/eza', category: 'cli', description: 'eza config' },\n\n // Fuzzy finders\n { path: '~/.fzf.zsh', category: 'cli', description: 'fzf Zsh integration' },\n { path: '~/.fzf.bash', category: 'cli', description: 'fzf Bash integration' },\n { path: '~/.config/fzf', category: 'cli', description: 'fzf config directory' },\n\n // Network tools\n { path: '~/.curlrc', category: 'cli', description: 'curl configuration' },\n { path: '~/.wgetrc', category: 'cli', description: 'wget configuration' },\n { path: '~/.netrc', category: 'cli', description: 'Network credentials', sensitive: true },\n { path: '~/.config/aria2', category: 'cli', description: 'aria2 download manager' },\n\n // System monitoring\n { path: '~/.config/htop', category: 'cli', description: 'htop config' },\n { path: '~/.config/btop', category: 'cli', description: 'btop config' },\n { path: '~/.config/bottom', category: 'cli', description: 'bottom config' },\n { path: '~/.config/glances', category: 'cli', description: 'Glances config' },\n\n // Other CLI tools\n { path: '~/.config/lazygit', category: 'cli', description: 'Lazygit config' },\n { path: '~/.config/lazydocker', category: 'cli', description: 'Lazydocker config' },\n { path: '~/.config/ranger', category: 'cli', description: 'Ranger file manager' },\n { path: '~/.config/lf', category: 'cli', description: 'lf file manager' },\n { path: '~/.config/yazi', category: 'cli', description: 'Yazi file manager' },\n { path: '~/.config/nnn', category: 'cli', description: 'nnn file manager' },\n { path: '~/.config/zoxide', category: 'cli', description: 'zoxide (smart cd)' },\n { path: '~/.config/atuin', category: 'cli', description: 'Atuin shell history' },\n { path: '~/.config/thefuck', category: 'cli', description: 'thefuck config' },\n { path: '~/.config/direnv', category: 'cli', description: 'direnv config' },\n { path: '~/.direnvrc', category: 'cli', description: 'direnv config (alt)' },\n { path: '~/.ackrc', category: 'cli', description: 'ack search config' },\n { path: '~/.agignore', category: 'cli', description: 'silver searcher ignore' },\n { path: '~/.editorconfig', category: 'cli', description: 'EditorConfig' },\n\n // ==================== LANGUAGES & PACKAGE MANAGERS ====================\n // Node.js\n { path: '~/.npmrc', category: 'languages', description: 'npm configuration' },\n { path: '~/.yarnrc', category: 'languages', description: 'Yarn configuration' },\n { path: '~/.config/yarn', category: 'languages', description: 'Yarn config directory' },\n { path: '~/.bunfig.toml', category: 'languages', description: 'Bun configuration' },\n { path: '~/.nvmrc', category: 'languages', description: 'nvm default version' },\n { path: '~/.node-version', category: 'languages', description: 'Node version file' },\n\n // Python\n { path: '~/.config/pip', category: 'languages', description: 'pip configuration' },\n { path: '~/.pip', category: 'languages', description: 'pip config (legacy)' },\n { path: '~/.pypirc', category: 'languages', description: 'PyPI configuration', sensitive: true },\n { path: '~/.python-version', category: 'languages', description: 'pyenv version' },\n { path: '~/.config/flake8', category: 'languages', description: 'Flake8 config' },\n { path: '~/.config/black', category: 'languages', description: 'Black formatter' },\n { path: '~/.config/ruff', category: 'languages', description: 'Ruff linter' },\n { path: '~/.pylintrc', category: 'languages', description: 'Pylint config' },\n { path: '~/.config/pypoetry', category: 'languages', description: 'Poetry config' },\n { path: '~/.config/pdm', category: 'languages', description: 'PDM config' },\n\n // Ruby\n { path: '~/.gemrc', category: 'languages', description: 'RubyGems configuration' },\n { path: '~/.irbrc', category: 'languages', description: 'IRB configuration' },\n { path: '~/.pryrc', category: 'languages', description: 'Pry configuration' },\n { path: '~/.ruby-version', category: 'languages', description: 'Ruby version file' },\n { path: '~/.bundle/config', category: 'languages', description: 'Bundler config' },\n\n // Rust\n { path: '~/.cargo/config.toml', category: 'languages', description: 'Cargo configuration' },\n { path: '~/.cargo/config', category: 'languages', description: 'Cargo config (legacy)' },\n { path: '~/.rustfmt.toml', category: 'languages', description: 'rustfmt config' },\n\n // Go\n { path: '~/.config/go', category: 'languages', description: 'Go configuration' },\n\n // Java/JVM\n { path: '~/.gradle/gradle.properties', category: 'languages', description: 'Gradle properties' },\n { path: '~/.m2/settings.xml', category: 'languages', description: 'Maven settings' },\n { path: '~/.sbt', category: 'languages', description: 'SBT config' },\n\n // Docker\n { path: '~/.docker/config.json', category: 'languages', description: 'Docker config' },\n\n // Kubernetes\n { path: '~/.kube/config', category: 'languages', description: 'kubectl config', sensitive: true },\n\n // Cloud\n { path: '~/.aws/config', category: 'languages', description: 'AWS CLI config' },\n { path: '~/.config/gcloud', category: 'languages', description: 'Google Cloud config' },\n\n // ==================== SSH & SECURITY ====================\n {\n path: '~/.ssh/config',\n category: 'ssh',\n description: 'SSH client configuration',\n sensitive: true,\n },\n {\n path: '~/.ssh/known_hosts',\n category: 'ssh',\n description: 'SSH known hosts',\n },\n {\n path: '~/.ssh/authorized_keys',\n category: 'ssh',\n description: 'Authorized SSH keys',\n },\n {\n path: '~/.ssh/rc',\n category: 'ssh',\n description: 'SSH connection script',\n },\n {\n path: '~/.gnupg/gpg.conf',\n category: 'ssh',\n description: 'GPG configuration',\n sensitive: true,\n },\n {\n path: '~/.gnupg/gpg-agent.conf',\n category: 'ssh',\n description: 'GPG agent configuration',\n },\n\n // ==================== XDG CONFIG APPS ====================\n { path: '~/.config/fontconfig', category: 'xdg', description: 'Font configuration' },\n { path: '~/.config/gtk-3.0', category: 'xdg', description: 'GTK3 settings' },\n { path: '~/.config/gtk-4.0', category: 'xdg', description: 'GTK4 settings' },\n { path: '~/.config/qt5ct', category: 'xdg', description: 'Qt5 settings' },\n { path: '~/.config/mimeapps.list', category: 'xdg', description: 'Default applications' },\n { path: '~/.config/user-dirs.dirs', category: 'xdg', description: 'XDG user directories' },\n { path: '~/.config/autostart', category: 'xdg', description: 'Autostart applications' },\n { path: '~/.config/environment.d', category: 'xdg', description: 'Environment variables' },\n { path: '~/.config/systemd/user', category: 'xdg', description: 'User systemd services', platform: 'linux' },\n { path: '~/.config/dunst', category: 'xdg', description: 'Dunst notifications', platform: 'linux' },\n { path: '~/.config/rofi', category: 'xdg', description: 'Rofi launcher', platform: 'linux' },\n { path: '~/.config/wofi', category: 'xdg', description: 'Wofi launcher', platform: 'linux' },\n\n // ==================== DESKTOP & WINDOW MANAGERS ====================\n // i3/sway\n { path: '~/.config/i3', category: 'desktop', description: 'i3 window manager', platform: 'linux' },\n { path: '~/.config/sway', category: 'desktop', description: 'Sway (Wayland i3)', platform: 'linux' },\n { path: '~/.config/i3status', category: 'desktop', description: 'i3status bar', platform: 'linux' },\n { path: '~/.config/i3status-rust', category: 'desktop', description: 'i3status-rust bar', platform: 'linux' },\n { path: '~/.config/waybar', category: 'desktop', description: 'Waybar', platform: 'linux' },\n { path: '~/.config/polybar', category: 'desktop', description: 'Polybar', platform: 'linux' },\n\n // Hyprland\n { path: '~/.config/hypr', category: 'desktop', description: 'Hyprland config', platform: 'linux' },\n\n // Other WMs\n { path: '~/.config/bspwm', category: 'desktop', description: 'bspwm config', platform: 'linux' },\n { path: '~/.config/sxhkd', category: 'desktop', description: 'sxhkd hotkeys', platform: 'linux' },\n { path: '~/.config/awesome', category: 'desktop', description: 'AwesomeWM config', platform: 'linux' },\n { path: '~/.config/openbox', category: 'desktop', description: 'Openbox config', platform: 'linux' },\n { path: '~/.config/qtile', category: 'desktop', description: 'Qtile config', platform: 'linux' },\n { path: '~/.config/herbstluftwm', category: 'desktop', description: 'herbstluftwm config', platform: 'linux' },\n\n // macOS window managers\n { path: '~/.yabairc', category: 'desktop', description: 'yabai config', platform: 'darwin' },\n { path: '~/.config/yabai', category: 'desktop', description: 'yabai config (XDG)', platform: 'darwin' },\n { path: '~/.skhdrc', category: 'desktop', description: 'skhd hotkeys', platform: 'darwin' },\n { path: '~/.config/skhd', category: 'desktop', description: 'skhd config (XDG)', platform: 'darwin' },\n { path: '~/.config/spacebar', category: 'desktop', description: 'spacebar config', platform: 'darwin' },\n { path: '~/.config/borders', category: 'desktop', description: 'borders config', platform: 'darwin' },\n { path: '~/.aerospace.toml', category: 'desktop', description: 'AeroSpace config', platform: 'darwin' },\n\n // Picom/Compton\n { path: '~/.config/picom', category: 'desktop', description: 'Picom compositor', platform: 'linux' },\n { path: '~/.config/picom.conf', category: 'desktop', description: 'Picom config (alt)', platform: 'linux' },\n\n // ==================== SCRIPTS & BINS ====================\n { path: '~/.local/bin', category: 'scripts', description: 'Local scripts and binaries' },\n { path: '~/bin', category: 'scripts', description: 'User bin directory' },\n { path: '~/.scripts', category: 'scripts', description: 'Custom scripts' },\n\n // ==================== MACOS SPECIFIC ====================\n { path: '~/.finicky.js', category: 'macos', description: 'Finicky browser picker', platform: 'darwin' },\n { path: '~/.config/karabiner', category: 'macos', description: 'Karabiner key remapping', platform: 'darwin' },\n { path: '~/.hammerspoon', category: 'macos', description: 'Hammerspoon automation', platform: 'darwin' },\n { path: '~/.config/raycast', category: 'macos', description: 'Raycast config', platform: 'darwin' },\n\n // ==================== MISCELLANEOUS ====================\n { path: '~/.config/neofetch', category: 'misc', description: 'Neofetch config' },\n { path: '~/.config/fastfetch', category: 'misc', description: 'Fastfetch config' },\n { path: '~/.config/onefetch', category: 'misc', description: 'Onefetch config' },\n { path: '~/.config/topgrade.toml', category: 'misc', description: 'Topgrade updater' },\n { path: '~/.config/youtube-dl', category: 'misc', description: 'youtube-dl config' },\n { path: '~/.config/yt-dlp', category: 'misc', description: 'yt-dlp config' },\n { path: '~/.config/mpv', category: 'misc', description: 'MPV media player' },\n { path: '~/.config/newsboat', category: 'misc', description: 'Newsboat RSS reader' },\n { path: '~/.config/cmus', category: 'misc', description: 'cmus music player' },\n { path: '~/.config/spotify-tui', category: 'misc', description: 'Spotify TUI' },\n { path: '~/.mailcap', category: 'misc', description: 'MIME type handlers' },\n { path: '~/.muttrc', category: 'misc', description: 'Mutt email client' },\n { path: '~/.config/mutt', category: 'misc', description: 'Mutt config directory' },\n { path: '~/.config/neomutt', category: 'misc', description: 'Neomutt config' },\n { path: '~/.Xresources', category: 'misc', description: 'X11 resources', platform: 'linux' },\n { path: '~/.Xmodmap', category: 'misc', description: 'X11 keymap', platform: 'linux' },\n { path: '~/.xinitrc', category: 'misc', description: 'X11 init script', platform: 'linux' },\n { path: '~/.xprofile', category: 'misc', description: 'X11 profile', platform: 'linux' },\n];\n\n/**\n * Patterns to exclude from detection\n * These are files/directories that should NEVER be tracked as they contain\n * ephemeral data, caches, or large binary files\n */\nexport const DEFAULT_EXCLUSION_PATTERNS = {\n // Cache directories - contain downloaded packages, build artifacts, etc.\n cacheDirectories: [\n '~/.cache',\n '~/.npm',\n '~/.yarn/cache',\n '~/.pnpm-store',\n '~/.bun/install/cache',\n '~/.cargo/registry',\n '~/.cargo/git',\n '~/.rustup/toolchains',\n '~/.go/pkg',\n '~/.m2/repository',\n '~/.gradle/caches',\n '~/.gradle/wrapper',\n '~/.ivy2/cache',\n '~/.sbt/boot',\n '~/.coursier/cache',\n '~/.pip/cache',\n '~/.local/pipx/venvs',\n '~/.pyenv/versions',\n '~/.rbenv/versions',\n '~/.nvm/versions',\n '~/.sdkman/candidates',\n '~/.local/share/virtualenvs',\n '~/.conda/pkgs',\n '~/.docker/buildx',\n '~/.docker/volumes',\n '~/.vagrant.d/boxes',\n '~/.terraform.d/plugins',\n '~/.composer/cache',\n '~/.cpan/build',\n '~/.cpanm/work',\n '~/.gem/ruby',\n '~/.thumbnails',\n '~/.local/share/Trash',\n '~/Library/Caches',\n '~/.node_modules',\n '~/.electron',\n ],\n\n // History and log files - contain ephemeral session data\n historyFiles: [\n '~/.bash_history',\n '~/.zsh_history',\n '~/.zhistory',\n '~/.sh_history',\n '~/.fish_history',\n '~/.config/fish/fish_history',\n '~/.lesshst',\n '~/.node_repl_history',\n '~/.python_history',\n '~/.irb_history',\n '~/.pry_history',\n '~/.mysql_history',\n '~/.psql_history',\n '~/.sqlite_history',\n '~/.rediscli_history',\n '~/.mongosh_history',\n '~/.dbshell',\n '~/.wget-hsts',\n '~/.recently-used',\n '~/.local/share/recently-used.xbel',\n '~/.viminfo',\n '~/.vim_mru_files',\n '~/.netrwhist',\n ],\n\n // Binary file extensions - images, fonts, compiled output\n binaryPatterns: [\n /\\.(png|jpg|jpeg|gif|ico|svg|webp|bmp|tiff?)$/i,\n /\\.(woff2?|ttf|otf|eot)$/i,\n /\\.(so|dylib|dll|exe|bin|app)$/i,\n /\\.(o|a|lib|obj|pyc|pyo|class)$/i,\n /\\.(db|sqlite|sqlite3|leveldb)$/i,\n /\\.(zip|tar|gz|bz2|xz|7z|rar)$/i,\n /\\.(pdf|doc|docx|xls|xlsx|ppt|pptx)$/i,\n /\\.(mp3|mp4|wav|flac|avi|mkv|mov)$/i,\n ],\n\n // Temporary and lock files\n tempFiles: [\n /\\.lock$/i,\n /\\.lockfile$/i,\n /\\.tmp$/i,\n /\\.temp$/i,\n /\\.swp$/i,\n /\\.swo$/i,\n /~$/,\n /\\.bak$/i,\n /\\.backup$/i,\n /\\.orig$/i,\n ],\n};\n\n/**\n * Check if a path should be excluded from detection/tracking\n */\nexport const shouldExcludeFile = (path: string): boolean => {\n // Normalize path to use ~ prefix\n // Handle both tilde paths and absolute paths that point to home directory\n let normalizedPath: string;\n if (path.startsWith('~/')) {\n // Already in tilde notation\n normalizedPath = path;\n } else if (path.startsWith(expandPath('~/'))) {\n // Absolute path within home directory - convert to tilde notation\n normalizedPath = path.replace(expandPath('~/'), '~/');\n } else if (isAbsolute(path)) {\n // Other absolute path - try to collapse to tilde notation\n normalizedPath = collapsePath(path);\n } else {\n // Relative path, keep as-is\n normalizedPath = path;\n }\n\n // Check cache directories (directory-aware prefix match)\n // Must match exactly or be a subdirectory (with /)\n for (const cacheDir of DEFAULT_EXCLUSION_PATTERNS.cacheDirectories) {\n if (\n normalizedPath === cacheDir ||\n normalizedPath.startsWith(cacheDir + '/')\n ) {\n return true;\n }\n }\n\n // Check history files (exact match)\n if (DEFAULT_EXCLUSION_PATTERNS.historyFiles.includes(normalizedPath)) {\n return true;\n }\n\n // Check binary patterns (regex on filename)\n const filename = basename(normalizedPath);\n for (const pattern of DEFAULT_EXCLUSION_PATTERNS.binaryPatterns) {\n if (pattern.test(filename)) {\n return true;\n }\n }\n\n // Check temp file patterns (regex on filename)\n for (const pattern of DEFAULT_EXCLUSION_PATTERNS.tempFiles) {\n if (pattern.test(filename)) {\n return true;\n }\n }\n\n return false;\n};\n\n/**\n * Check if a path should be included for current platform\n */\nconst shouldIncludeForPlatform = (item: { platform?: string }): boolean => {\n if (!item.platform || item.platform === 'all') return true;\n if (item.platform === 'darwin' && IS_MACOS) return true;\n if (item.platform === 'linux' && IS_LINUX) return true;\n return false;\n};\n\n/**\n * Get file/directory size\n */\nconst getSize = async (path: string): Promise<number | undefined> => {\n try {\n const stats = await stat(path);\n return stats.size;\n } catch {\n return undefined;\n }\n};\n\n/**\n * Check if path is a directory\n */\nconst isDirectory = async (path: string): Promise<boolean> => {\n try {\n const stats = await stat(path);\n return stats.isDirectory();\n } catch {\n return false;\n }\n};\n\n/**\n * Scan system for existing dotfiles\n * @param options - Optional configuration for detection\n * @param options.includeExcluded - If true, include files that match exclusion patterns (default: false). Set to true when you need to detect all dotfiles regardless of exclusion rules, such as for manual review or special operations.\n */\nexport const detectDotfiles = async (options?: {\n includeExcluded?: boolean;\n}): Promise<DetectedFile[]> => {\n const detected: DetectedFile[] = [];\n const includeExcluded = options?.includeExcluded ?? false;\n\n for (const pattern of DOTFILE_PATTERNS) {\n // Skip if not for current platform\n if (!shouldIncludeForPlatform(pattern)) continue;\n\n // Skip if matches exclusion patterns (unless explicitly including)\n if (!includeExcluded && shouldExcludeFile(pattern.path)) continue;\n\n const fullPath = expandPath(pattern.path);\n\n if (await pathExists(fullPath)) {\n const isDir = await isDirectory(fullPath);\n const size = await getSize(fullPath);\n\n detected.push({\n path: pattern.path,\n name: basename(pattern.path),\n category: pattern.category,\n description: pattern.description,\n isDirectory: isDir,\n size,\n sensitive: pattern.sensitive,\n exclude: pattern.exclude,\n });\n }\n }\n\n return detected;\n};\n\n/**\n * Group detected files by category\n */\nexport const groupByCategory = (\n files: DetectedFile[]\n): Record<string, DetectedFile[]> => {\n const grouped: Record<string, DetectedFile[]> = {};\n\n for (const file of files) {\n if (!grouped[file.category]) {\n grouped[file.category] = [];\n }\n grouped[file.category].push(file);\n }\n\n return grouped;\n};\n\n/**\n * Get SSH files that are safe to backup (no private keys)\n */\nexport const getSafeSSHFiles = async (): Promise<string[]> => {\n const sshDir = expandPath('~/.ssh');\n const safeFiles: string[] = [];\n\n if (!(await pathExists(sshDir))) {\n return safeFiles;\n }\n\n try {\n const entries = await readdir(sshDir);\n\n for (const entry of entries) {\n // Skip private keys and other sensitive files\n if (\n entry.endsWith('.pub') ||\n entry === 'config' ||\n entry === 'known_hosts' ||\n entry === 'authorized_keys' ||\n entry === 'rc' ||\n entry === 'environment'\n ) {\n safeFiles.push(join('~/.ssh', entry));\n }\n }\n } catch {\n // Ignore errors\n }\n\n return safeFiles;\n};\n\n/**\n * Format file size for display\n */\nexport const formatSize = (bytes: number | undefined): string => {\n if (bytes === undefined) return '';\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;\n};\n\n/**\n * Get count of files in each category\n */\nexport const getCategoryCounts = (\n files: DetectedFile[]\n): Record<string, number> => {\n const counts: Record<string, number> = {};\n\n for (const file of files) {\n counts[file.category] = (counts[file.category] || 0) + 1;\n }\n\n return counts;\n};\n","import { createHash } from 'crypto';\nimport { readFile, stat, lstat, readdir, copyFile, symlink, unlink, rm } from 'fs/promises';\nimport { copy, ensureDir } from 'fs-extra';\nimport { join, dirname, basename } from 'path';\nimport { constants } from 'fs';\nimport { FileNotFoundError, PermissionError } from '../errors.js';\nimport { expandPath, pathExists, isDirectory } from './paths.js';\n\nexport interface FileInfo {\n path: string;\n isDirectory: boolean;\n isSymlink: boolean;\n size: number;\n permissions: string;\n modified: Date;\n}\n\nexport interface CopyResult {\n source: string;\n destination: string;\n fileCount: number;\n totalSize: number;\n}\n\nexport const getFileChecksum = async (filepath: string): Promise<string> => {\n const expandedPath = expandPath(filepath);\n\n if (await isDirectory(expandedPath)) {\n // For directories, create a hash of all file checksums\n const files = await getDirectoryFiles(expandedPath);\n const hashes: string[] = [];\n\n for (const file of files) {\n const content = await readFile(file);\n hashes.push(createHash('sha256').update(content).digest('hex'));\n }\n\n return createHash('sha256').update(hashes.join('')).digest('hex');\n }\n\n const content = await readFile(expandedPath);\n return createHash('sha256').update(content).digest('hex');\n};\n\nexport const getFileInfo = async (filepath: string): Promise<FileInfo> => {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n throw new FileNotFoundError(filepath);\n }\n\n try {\n const stats = await stat(expandedPath);\n const permissions = (stats.mode & 0o777).toString(8).padStart(3, '0');\n\n return {\n path: expandedPath,\n isDirectory: stats.isDirectory(),\n isSymlink: stats.isSymbolicLink(),\n size: stats.size,\n permissions,\n modified: stats.mtime,\n };\n } catch (error) {\n throw new PermissionError(filepath, 'read');\n }\n};\n\nexport const getDirectoryFiles = async (dirpath: string): Promise<string[]> => {\n const expandedPath = expandPath(dirpath);\n const files: string[] = [];\n\n // Skip common temporary/cache files and git repos that change frequently\n const skipPatterns = [\n '.DS_Store',\n 'Thumbs.db',\n '.git', // Skip git directories to prevent nested repos\n '.gitignore',\n 'node_modules',\n '.cache',\n '__pycache__',\n '*.pyc',\n '*.swp',\n '*.tmp',\n '.npmrc',\n 'package-lock.json',\n 'yarn.lock',\n 'pnpm-lock.yaml',\n ];\n\n let entries;\n try {\n entries = await readdir(expandedPath, { withFileTypes: true });\n } catch (error) {\n // Handle permission errors and other read failures gracefully\n return files;\n }\n\n for (const entry of entries) {\n const entryPath = join(expandedPath, entry.name);\n \n const shouldSkip = skipPatterns.some(pattern => {\n if (pattern.includes('*')) {\n // Escape special regex characters (especially .) before replacing * with .*\n const escapedPattern = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n const regex = new RegExp('^' + escapedPattern + '$');\n return regex.test(entry.name);\n }\n return entry.name === pattern;\n });\n \n if (shouldSkip) {\n continue;\n }\n\n try {\n // Use lstat to detect symlinks (stat follows symlinks, lstat doesn't)\n const lstats = await lstat(entryPath);\n\n // Skip symlinks to prevent infinite recursion loops\n if (lstats.isSymbolicLink()) {\n continue;\n }\n\n if (entry.isDirectory()) {\n const subFiles = await getDirectoryFiles(entryPath);\n files.push(...subFiles);\n } else if (entry.isFile()) {\n files.push(entryPath);\n }\n } catch {\n // Skip entries we can't access (permission errors, etc.)\n continue;\n }\n }\n\n return files.sort();\n};\n\nexport const getDirectoryFileCount = async (dirpath: string): Promise<number> => {\n const files = await getDirectoryFiles(dirpath);\n return files.length;\n};\n\nexport const copyFileOrDir = async (\n source: string,\n destination: string,\n options?: { overwrite?: boolean }\n): Promise<CopyResult> => {\n const expandedSource = expandPath(source);\n const expandedDest = expandPath(destination);\n\n if (!(await pathExists(expandedSource))) {\n throw new FileNotFoundError(source);\n }\n\n // Ensure destination directory exists\n await ensureDir(dirname(expandedDest));\n\n const sourceIsDir = await isDirectory(expandedSource);\n\n try {\n const shouldOverwrite = options?.overwrite ?? true;\n\n if (sourceIsDir) {\n // Copy directory but skip .git and other problematic files\n await copy(expandedSource, expandedDest, { \n overwrite: shouldOverwrite,\n filter: (src: string) => {\n const name = basename(src);\n // Skip .git directories, node_modules, and cache directories\n const skipDirs = ['.git', 'node_modules', '.cache', '__pycache__', '.DS_Store'];\n return !skipDirs.includes(name);\n }\n });\n const fileCount = await getDirectoryFileCount(expandedDest);\n const files = await getDirectoryFiles(expandedDest);\n let totalSize = 0;\n for (const file of files) {\n const stats = await stat(file);\n totalSize += stats.size;\n }\n return { source: expandedSource, destination: expandedDest, fileCount, totalSize };\n } else {\n // Use COPYFILE_EXCL flag to prevent overwriting when overwrite is false\n // If overwrite is true (default), use mode 0 which allows overwriting\n const copyFlags = shouldOverwrite ? 0 : constants.COPYFILE_EXCL;\n await copyFile(expandedSource, expandedDest, copyFlags);\n const stats = await stat(expandedDest);\n return { source: expandedSource, destination: expandedDest, fileCount: 1, totalSize: stats.size };\n }\n } catch (error) {\n throw new PermissionError(destination, 'write');\n }\n};\n\nexport const createSymlink = async (\n target: string,\n linkPath: string,\n options?: { overwrite?: boolean }\n): Promise<void> => {\n const expandedTarget = expandPath(target);\n const expandedLink = expandPath(linkPath);\n\n if (!(await pathExists(expandedTarget))) {\n throw new FileNotFoundError(target);\n }\n\n // Ensure link parent directory exists\n await ensureDir(dirname(expandedLink));\n\n // Remove existing file/symlink if overwrite is true\n if (options?.overwrite && (await pathExists(expandedLink))) {\n await unlink(expandedLink);\n }\n\n try {\n await symlink(expandedTarget, expandedLink);\n } catch (error) {\n throw new PermissionError(linkPath, 'create symlink');\n }\n};\n\nexport const deleteFileOrDir = async (filepath: string): Promise<void> => {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n return; // Already deleted\n }\n\n try {\n if (await isDirectory(expandedPath)) {\n await rm(expandedPath, { recursive: true });\n } else {\n await unlink(expandedPath);\n }\n } catch (error) {\n throw new PermissionError(filepath, 'delete');\n }\n};\n\nexport const ensureDirectory = async (dirpath: string): Promise<void> => {\n const expandedPath = expandPath(dirpath);\n await ensureDir(expandedPath);\n};\n\nexport const moveFile = async (\n source: string,\n destination: string,\n options?: { overwrite?: boolean }\n): Promise<void> => {\n await copyFileOrDir(source, destination, options);\n await deleteFileOrDir(source);\n};\n\nexport const hasFileChanged = async (\n file1: string,\n file2: string\n): Promise<boolean> => {\n const expandedFile1 = expandPath(file1);\n const expandedFile2 = expandPath(file2);\n\n // If either doesn't exist, they're different\n if (!(await pathExists(expandedFile1)) || !(await pathExists(expandedFile2))) {\n return true;\n }\n\n const checksum1 = await getFileChecksum(expandedFile1);\n const checksum2 = await getFileChecksum(expandedFile2);\n\n return checksum1 !== checksum2;\n};\n\nexport const getFilePermissions = async (filepath: string): Promise<string> => {\n const expandedPath = expandPath(filepath);\n const stats = await stat(expandedPath);\n return (stats.mode & 0o777).toString(8).padStart(3, '0');\n};\n\nexport const setFilePermissions = async (filepath: string, mode: string): Promise<void> => {\n const expandedPath = expandPath(filepath);\n const { chmod } = await import('fs/promises');\n await chmod(expandedPath, parseInt(mode, 8));\n};\n\nexport const formatBytes = (bytes: number): string => {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;\n};\n\n// ============================================================================\n// File Size Utilities for Large File Detection\n// ============================================================================\n\nexport const SIZE_WARN_THRESHOLD = 50 * 1024 * 1024; // 50MB\nexport const SIZE_BLOCK_THRESHOLD = 100 * 1024 * 1024; // 100MB\n\n/**\n * Get total size of a file or directory recursively\n */\nexport const getFileSizeRecursive = async (filepath: string): Promise<number> => {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n return 0;\n }\n\n const stats = await stat(expandedPath);\n\n if (!stats.isDirectory()) {\n return stats.size;\n }\n\n // Directory: sum all file sizes\n const files = await getDirectoryFiles(expandedPath);\n let totalSize = 0;\n\n for (const file of files) {\n try {\n const fileStats = await stat(file);\n totalSize += fileStats.size;\n } catch {\n // Skip files we can't access\n continue;\n }\n }\n\n return totalSize;\n};\n\n/**\n * Format file size in human-readable format (e.g., \"50.2 MB\")\n * Adds validation to handle invalid/negative values safely\n */\nexport const formatFileSize = (bytes: number): string => {\n // Normalize invalid or negative values to 0 to avoid surprising output\n if (!Number.isFinite(bytes) || bytes < 0) {\n bytes = 0;\n }\n return formatBytes(bytes);\n};\n\n/**\n * Check if file size exceeds warning or blocking thresholds\n */\nexport const checkFileSizeThreshold = async (\n filepath: string\n): Promise<{ warn: boolean; block: boolean; size: number }> => {\n const size = await getFileSizeRecursive(filepath);\n\n return {\n warn: size >= SIZE_WARN_THRESHOLD,\n block: size >= SIZE_BLOCK_THRESHOLD,\n size,\n };\n};\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport { expandPath, collapsePath, getDestinationPath, getRelativeDestination, generateFileId, sanitizeFilename, detectCategory } from './paths.js';\nimport { addFileToManifest } from './manifest.js';\nimport { copyFileOrDir, createSymlink, getFileChecksum, getFileInfo } from './files.js';\nimport { loadConfig } from './config.js';\nimport { CATEGORIES } from '../constants.js';\nimport { ensureDir } from 'fs-extra';\nimport { dirname } from 'path';\nimport type { FileStrategy } from '../types.js';\n\nexport interface FileToTrack {\n path: string;\n category?: string;\n}\n\nexport interface FileTrackingOptions {\n /**\n * Show category icons after file names\n */\n showCategory?: boolean;\n\n /**\n * Custom strategy (copy, symlink, etc.)\n */\n strategy?: FileStrategy;\n\n // TODO: Encryption and templating are planned for a future version\n // /**\n // * Encrypt files\n // */\n // encrypt?: boolean;\n //\n // /**\n // * Treat as template\n // */\n // template?: boolean;\n\n /**\n * Delay between file operations in milliseconds\n * Automatically reduced for large batches (>=50 files)\n */\n delayBetween?: number;\n\n /**\n * Action verb for display (e.g., \"Tracking\", \"Adding\", \"Processing\")\n */\n actionVerb?: string;\n\n /**\n * Callback called after each file is processed\n */\n onProgress?: (current: number, total: number) => void;\n}\n\nexport interface FileTrackingResult {\n succeeded: number;\n failed: number;\n errors: Array<{ path: string; error: Error }>;\n sensitiveFiles: string[];\n}\n\n/**\n * Pattern matching for sensitive files\n */\nconst SENSITIVE_FILE_PATTERNS = [\n /^\\.netrc$/,\n /^\\.aws\\/credentials$/,\n /^\\.docker\\/config\\.json$/,\n /^\\.npmrc$/,\n /^\\.pypirc$/,\n /^\\.kube\\/config$/,\n /^\\.ssh\\/config$/,\n /^\\.gnupg\\//,\n /credentials/i,\n /secrets?/i,\n /tokens?\\.json$/i,\n /\\.env$/,\n /\\.env\\./,\n];\n\n/**\n * Check if a path contains potentially sensitive data\n */\nconst isSensitiveFile = (path: string): boolean => {\n const pathToTest = path.startsWith('~/') ? path.slice(2) : path;\n for (const pattern of SENSITIVE_FILE_PATTERNS) {\n if (pattern.test(pathToTest)) {\n return true;\n }\n }\n return false;\n};\n\n/**\n * Shared file tracking logic used by add, scan, and init commands.\n * Processes files one by one with beautiful progress display.\n * \n * @param files - Array of files to track with their paths and optional categories\n * @param tuckDir - Path to the tuck directory\n * @param options - Options for tracking behavior and display\n * @returns Result containing success/failure counts and accumulated errors\n */\nexport const trackFilesWithProgress = async (\n files: FileToTrack[],\n tuckDir: string,\n options: FileTrackingOptions = {}\n): Promise<FileTrackingResult> => {\n const {\n showCategory = true,\n strategy: customStrategy,\n // TODO: Encryption and templating are planned for a future version\n // encrypt = false,\n // template = false,\n actionVerb = 'Tracking',\n onProgress,\n } = options;\n\n // Adaptive delay: reduce delay for large batches\n let { delayBetween } = options;\n if (delayBetween === undefined) {\n delayBetween = files.length >= 50 ? 10 : 30; // 10ms for large batches, 30ms for small\n }\n\n const config = await loadConfig(tuckDir);\n const strategy: FileStrategy = customStrategy || config.files.strategy || 'copy';\n const total = files.length;\n const errors: Array<{ path: string; error: Error }> = [];\n const sensitiveFiles: string[] = [];\n let succeeded = 0;\n\n console.log();\n console.log(chalk.bold.cyan(`${actionVerb} ${total} ${total === 1 ? 'file' : 'files'}...`));\n console.log(chalk.dim('─'.repeat(50)));\n console.log();\n\n for (let i = 0; i < files.length; i++) {\n const file = files[i];\n const expandedPath = expandPath(file.path);\n const indexStr = chalk.dim(`[${i + 1}/${total}]`);\n const category = file.category || detectCategory(expandedPath);\n const filename = sanitizeFilename(expandedPath);\n const categoryInfo = CATEGORIES[category];\n const icon = categoryInfo?.icon || '○';\n\n // Show spinner while processing\n const spinner = ora({\n text: `${indexStr} ${actionVerb} ${chalk.cyan(collapsePath(file.path))}`,\n color: 'cyan',\n spinner: 'dots',\n indent: 2,\n }).start();\n\n try {\n // Get destination path\n const destination = getDestinationPath(tuckDir, category, filename);\n\n // Ensure category directory exists\n await ensureDir(dirname(destination));\n\n // Copy or symlink based on strategy\n if (strategy === 'symlink') {\n // Create symlink from destination to source (repo points to original)\n await createSymlink(expandedPath, destination, { overwrite: true });\n } else {\n // Default: copy file into the repository\n await copyFileOrDir(expandedPath, destination, { overwrite: true });\n }\n\n // Get file info\n const checksum = await getFileChecksum(destination);\n const info = await getFileInfo(expandedPath);\n const now = new Date().toISOString();\n\n // Generate unique ID\n const id = generateFileId(file.path);\n\n // Add to manifest\n await addFileToManifest(tuckDir, id, {\n source: collapsePath(file.path),\n destination: getRelativeDestination(category, filename),\n category,\n strategy,\n // TODO: Encryption and templating are planned for a future version\n encrypted: false,\n template: false,\n permissions: info.permissions,\n added: now,\n modified: now,\n checksum,\n });\n\n spinner.stop();\n const categoryStr = showCategory ? chalk.dim(` ${icon} ${category}`) : '';\n console.log(` ${chalk.green('✓')} ${indexStr} ${collapsePath(file.path)}${categoryStr}`);\n\n // Track sensitive files for warning at the end\n if (isSensitiveFile(collapsePath(file.path))) {\n sensitiveFiles.push(file.path);\n }\n\n succeeded++;\n\n // Call progress callback\n if (onProgress) {\n onProgress(i + 1, total);\n }\n\n // Small delay for visual effect (unless it's the last item)\n if (i < files.length - 1 && delayBetween > 0) {\n await new Promise(resolve => setTimeout(resolve, delayBetween));\n }\n } catch (error) {\n spinner.stop();\n const errorObj = error instanceof Error ? error : new Error(String(error));\n errors.push({ path: file.path, error: errorObj });\n console.log(` ${chalk.red('✗')} ${indexStr} ${collapsePath(file.path)} ${chalk.red('- failed')}`);\n }\n }\n\n // Show summary\n console.log();\n if (succeeded > 0) {\n console.log(chalk.green('✓'), chalk.bold(`Tracked ${succeeded} ${succeeded === 1 ? 'file' : 'files'} successfully`));\n }\n\n // Show accumulated errors if any\n if (errors.length > 0) {\n console.log();\n console.log(chalk.red('✗'), chalk.bold(`Failed to track ${errors.length} ${errors.length === 1 ? 'file' : 'files'}:`));\n for (const { path, error } of errors) {\n console.log(chalk.dim(` • ${collapsePath(path)}: ${error.message}`));\n }\n }\n\n // Warn about sensitive files at the end (not inline to avoid clutter)\n if (sensitiveFiles.length > 0) {\n console.log();\n console.log(chalk.yellow('⚠'), chalk.yellow('Warning: Some files may contain sensitive data:'));\n for (const path of sensitiveFiles) {\n console.log(chalk.dim(` • ${collapsePath(path)}`));\n }\n console.log(chalk.dim(' Make sure your repository is private!'));\n }\n\n return {\n succeeded,\n failed: errors.length,\n errors,\n sensitiveFiles,\n };\n};\n","import { join } from 'path';\nimport { readdir, rm } from 'fs/promises';\nimport { copy, ensureDir, pathExists } from 'fs-extra';\nimport { BACKUP_DIR } from '../constants.js';\nimport { expandPath, collapsePath, pathExists as checkPathExists } from './paths.js';\n\nexport interface BackupInfo {\n path: string;\n date: Date;\n files: string[];\n}\n\nexport interface BackupResult {\n originalPath: string;\n backupPath: string;\n date: Date;\n}\n\nconst getBackupDir = (): string => {\n return expandPath(BACKUP_DIR);\n};\n\nconst formatDateForBackup = (date: Date): string => {\n return date.toISOString().slice(0, 10); // YYYY-MM-DD\n};\n\nconst getTimestampedBackupDir = (date: Date): string => {\n const backupRoot = getBackupDir();\n const timestamp = formatDateForBackup(date);\n return join(backupRoot, timestamp);\n};\n\nexport const createBackup = async (\n sourcePath: string,\n customBackupDir?: string\n): Promise<BackupResult> => {\n const expandedSource = expandPath(sourcePath);\n const date = new Date();\n\n if (!(await checkPathExists(expandedSource))) {\n throw new Error(`Source path does not exist: ${sourcePath}`);\n }\n\n // Create backup directory with date\n const backupRoot = customBackupDir\n ? expandPath(customBackupDir)\n : getTimestampedBackupDir(date);\n await ensureDir(backupRoot);\n\n // Generate backup filename that preserves structure\n const collapsed = collapsePath(expandedSource);\n const backupName = collapsed\n .replace(/^~\\//, '')\n .replace(/\\//g, '_')\n .replace(/^\\./, 'dot-');\n\n // Add timestamp to handle multiple backups of same file in a day\n const timestamp = date.toISOString().replace(/[:.]/g, '-').slice(11, 19);\n const backupPath = join(backupRoot, `${backupName}_${timestamp}`);\n\n await copy(expandedSource, backupPath, { overwrite: true });\n\n return {\n originalPath: expandedSource,\n backupPath,\n date,\n };\n};\n\nexport const createMultipleBackups = async (\n sourcePaths: string[],\n customBackupDir?: string\n): Promise<BackupResult[]> => {\n const results: BackupResult[] = [];\n\n for (const path of sourcePaths) {\n const result = await createBackup(path, customBackupDir);\n results.push(result);\n }\n\n return results;\n};\n\nexport const listBackups = async (): Promise<BackupInfo[]> => {\n const backupRoot = getBackupDir();\n\n if (!(await pathExists(backupRoot))) {\n return [];\n }\n\n const backups: BackupInfo[] = [];\n const dateDirs = await readdir(backupRoot, { withFileTypes: true });\n\n for (const dateDir of dateDirs) {\n if (!dateDir.isDirectory()) continue;\n\n const datePath = join(backupRoot, dateDir.name);\n const files = await readdir(datePath);\n\n // Parse date from directory name\n const dateMatch = dateDir.name.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n if (!dateMatch) continue;\n\n const date = new Date(`${dateMatch[1]}-${dateMatch[2]}-${dateMatch[3]}`);\n\n backups.push({\n path: datePath,\n date,\n files: files.map((f) => join(datePath, f)),\n });\n }\n\n // Sort by date, newest first\n return backups.sort((a, b) => b.date.getTime() - a.date.getTime());\n};\n\nexport const getBackupsByDate = async (date: Date): Promise<string[]> => {\n const backupDir = getTimestampedBackupDir(date);\n\n if (!(await pathExists(backupDir))) {\n return [];\n }\n\n const files = await readdir(backupDir);\n return files.map((f) => join(backupDir, f));\n};\n\nexport const restoreBackup = async (backupPath: string, targetPath: string): Promise<void> => {\n const expandedBackup = expandPath(backupPath);\n const expandedTarget = expandPath(targetPath);\n\n if (!(await checkPathExists(expandedBackup))) {\n throw new Error(`Backup not found: ${backupPath}`);\n }\n\n // Create backup of current state before restoring\n if (await checkPathExists(expandedTarget)) {\n await createBackup(expandedTarget);\n }\n\n await copy(expandedBackup, expandedTarget, { overwrite: true });\n};\n\nexport const deleteBackup = async (backupPath: string): Promise<void> => {\n const expandedPath = expandPath(backupPath);\n\n if (await checkPathExists(expandedPath)) {\n await rm(expandedPath, { recursive: true });\n }\n};\n\nexport const cleanOldBackups = async (daysToKeep: number): Promise<number> => {\n const backups = await listBackups();\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);\n\n let deletedCount = 0;\n\n for (const backup of backups) {\n if (backup.date < cutoffDate) {\n await rm(backup.path, { recursive: true });\n deletedCount++;\n }\n }\n\n return deletedCount;\n};\n\nexport const getBackupSize = async (): Promise<number> => {\n const backups = await listBackups();\n let totalSize = 0;\n\n for (const backup of backups) {\n for (const file of backup.files) {\n const { stat } = await import('fs/promises');\n try {\n const stats = await stat(file);\n totalSize += stats.size;\n } catch {\n // Ignore errors\n }\n }\n }\n\n return totalSize;\n};\n","import { exec } from 'child_process';\nimport { promisify } from 'util';\nimport chalk from 'chalk';\nimport { loadConfig } from './config.js';\nimport { logger } from '../ui/logger.js';\nimport { prompts } from '../ui/prompts.js';\n\nconst execAsync = promisify(exec);\n\nexport type HookType = 'preSync' | 'postSync' | 'preRestore' | 'postRestore';\n\nexport interface HookResult {\n success: boolean;\n output?: string;\n error?: string;\n skipped?: boolean;\n}\n\nexport interface HookOptions {\n silent?: boolean;\n skipHooks?: boolean;\n trustHooks?: boolean;\n}\n\n/**\n * SECURITY: This function executes shell commands from the configuration file.\n * When cloning from untrusted repositories, hooks could contain malicious commands.\n * We require explicit user confirmation before executing any hooks.\n */\nexport const runHook = async (\n hookType: HookType,\n tuckDir: string,\n options?: HookOptions\n): Promise<HookResult> => {\n // If hooks are explicitly disabled, skip execution\n if (options?.skipHooks) {\n return { success: true, skipped: true };\n }\n\n const config = await loadConfig(tuckDir);\n const command = config.hooks[hookType];\n\n if (!command) {\n return { success: true };\n }\n\n // SECURITY: Always show the hook command and require confirmation\n // unless trustHooks is explicitly set (for non-interactive/scripted use)\n if (!options?.trustHooks) {\n console.log();\n console.log(chalk.yellow.bold('WARNING: Hook Execution'));\n console.log(chalk.dim('─'.repeat(50)));\n console.log(chalk.white(`Hook type: ${chalk.cyan(hookType)}`));\n console.log(chalk.white('Command:'));\n console.log(chalk.red(` ${command}`));\n console.log(chalk.dim('─'.repeat(50)));\n console.log(\n chalk.yellow(\n 'SECURITY: Hooks can execute arbitrary commands on your system.'\n )\n );\n console.log(\n chalk.yellow(\n 'Only proceed if you trust the source of this configuration.'\n )\n );\n console.log();\n\n const confirmed = await prompts.confirm(\n 'Execute this hook?',\n false // Default to NO for safety\n );\n\n if (!confirmed) {\n logger.warning(`Hook ${hookType} skipped by user`);\n return { success: true, skipped: true };\n }\n }\n\n if (!options?.silent) {\n logger.dim(`Running ${hookType} hook...`);\n }\n\n try {\n const { stdout, stderr } = await execAsync(command, {\n cwd: tuckDir,\n timeout: 30000, // 30 second timeout\n env: {\n ...process.env,\n TUCK_DIR: tuckDir,\n TUCK_HOOK: hookType,\n },\n });\n\n if (stdout && !options?.silent) {\n logger.dim(stdout.trim());\n }\n\n if (stderr && !options?.silent) {\n logger.warning(stderr.trim());\n }\n\n return { success: true, output: stdout };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (!options?.silent) {\n logger.error(`Hook ${hookType} failed: ${errorMessage}`);\n }\n\n return { success: false, error: errorMessage };\n }\n};\n\nexport const runPreSyncHook = async (\n tuckDir: string,\n options?: HookOptions\n): Promise<HookResult> => {\n return runHook('preSync', tuckDir, options);\n};\n\nexport const runPostSyncHook = async (\n tuckDir: string,\n options?: HookOptions\n): Promise<HookResult> => {\n return runHook('postSync', tuckDir, options);\n};\n\nexport const runPreRestoreHook = async (\n tuckDir: string,\n options?: HookOptions\n): Promise<HookResult> => {\n return runHook('preRestore', tuckDir, options);\n};\n\nexport const runPostRestoreHook = async (\n tuckDir: string,\n options?: HookOptions\n): Promise<HookResult> => {\n return runHook('postRestore', tuckDir, options);\n};\n\nexport const hasHook = async (hookType: HookType, tuckDir: string): Promise<boolean> => {\n const config = await loadConfig(tuckDir);\n return Boolean(config.hooks[hookType]);\n};\n\nexport const getHookCommand = async (\n hookType: HookType,\n tuckDir: string\n): Promise<string | undefined> => {\n const config = await loadConfig(tuckDir);\n return config.hooks[hookType];\n};\n\n/**\n * Check if any hooks are configured\n */\nexport const hasAnyHooks = async (tuckDir: string): Promise<boolean> => {\n const config = await loadConfig(tuckDir);\n return Boolean(\n config.hooks.preSync ||\n config.hooks.postSync ||\n config.hooks.preRestore ||\n config.hooks.postRestore\n );\n};\n\n/**\n * Get all configured hooks for display\n */\nexport const getAllHooks = async (\n tuckDir: string\n): Promise<Record<HookType, string | undefined>> => {\n const config = await loadConfig(tuckDir);\n return {\n preSync: config.hooks.preSync,\n postSync: config.hooks.postSync,\n preRestore: config.hooks.preRestore,\n postRestore: config.hooks.postRestore,\n };\n};\n","import { Command } from 'commander';\nimport { join } from 'path';\nimport { colors as c } from '../ui/theme.js';\nimport { chmod, stat } from 'fs/promises';\nimport { prompts, logger, withSpinner } from '../ui/index.js';\nimport { getTuckDir, expandPath, pathExists, collapsePath } from '../lib/paths.js';\nimport { loadManifest, getAllTrackedFiles, getTrackedFileBySource } from '../lib/manifest.js';\nimport { loadConfig } from '../lib/config.js';\nimport { copyFileOrDir, createSymlink } from '../lib/files.js';\nimport { createBackup } from '../lib/backup.js';\nimport { runPreRestoreHook, runPostRestoreHook, type HookOptions } from '../lib/hooks.js';\nimport { NotInitializedError, FileNotFoundError } from '../errors.js';\nimport { CATEGORIES } from '../constants.js';\nimport type { RestoreOptions } from '../types.js';\n\n/**\n * Fix permissions for SSH files after restore\n * SSH requires strict permissions: 700 for directories, 600 for private files\n */\nconst fixSSHPermissions = async (path: string): Promise<void> => {\n const expandedPath = expandPath(path);\n\n // Only fix permissions for SSH files\n // Check for files inside .ssh/ directory or the .ssh directory itself\n if (!path.includes('.ssh/') && !path.endsWith('.ssh')) {\n return;\n }\n\n try {\n const stats = await stat(expandedPath);\n\n if (stats.isDirectory()) {\n // Directories should be 700\n await chmod(expandedPath, 0o700);\n } else {\n // Files should be 600\n await chmod(expandedPath, 0o600);\n }\n } catch {\n // Ignore permission errors (might be on Windows)\n }\n};\n\n/**\n * Fix GPG permissions after restore\n */\nconst fixGPGPermissions = async (path: string): Promise<void> => {\n const expandedPath = expandPath(path);\n\n // Only fix permissions for GPG files\n // Check for files inside .gnupg/ directory or the .gnupg directory itself\n if (!path.includes('.gnupg/') && !path.endsWith('.gnupg')) {\n return;\n }\n\n try {\n const stats = await stat(expandedPath);\n\n if (stats.isDirectory()) {\n await chmod(expandedPath, 0o700);\n } else {\n await chmod(expandedPath, 0o600);\n }\n } catch {\n // Ignore permission errors\n }\n};\n\ninterface FileToRestore {\n id: string;\n source: string;\n destination: string;\n category: string;\n existsAtTarget: boolean;\n}\n\nconst prepareFilesToRestore = async (\n tuckDir: string,\n paths?: string[]\n): Promise<FileToRestore[]> => {\n const allFiles = await getAllTrackedFiles(tuckDir);\n const filesToRestore: FileToRestore[] = [];\n\n if (paths && paths.length > 0) {\n // Restore specific files\n for (const path of paths) {\n const expandedPath = expandPath(path);\n const collapsedPath = collapsePath(expandedPath);\n\n const tracked = await getTrackedFileBySource(tuckDir, collapsedPath);\n if (!tracked) {\n throw new FileNotFoundError(`Not tracked: ${path}`);\n }\n\n filesToRestore.push({\n id: tracked.id,\n source: tracked.file.source,\n destination: join(tuckDir, tracked.file.destination),\n category: tracked.file.category,\n existsAtTarget: await pathExists(expandedPath),\n });\n }\n } else {\n // Restore all files\n for (const [id, file] of Object.entries(allFiles)) {\n const targetPath = expandPath(file.source);\n filesToRestore.push({\n id,\n source: file.source,\n destination: join(tuckDir, file.destination),\n category: file.category,\n existsAtTarget: await pathExists(targetPath),\n });\n }\n }\n\n return filesToRestore;\n};\n\nconst restoreFiles = async (\n tuckDir: string,\n files: FileToRestore[],\n options: RestoreOptions\n): Promise<number> => {\n const config = await loadConfig(tuckDir);\n const useSymlink = options.symlink || config.files.strategy === 'symlink';\n const shouldBackup = options.backup ?? config.files.backupOnRestore;\n\n // Prepare hook options\n const hookOptions: HookOptions = {\n skipHooks: options.noHooks,\n trustHooks: options.trustHooks,\n };\n\n // Run pre-restore hook\n await runPreRestoreHook(tuckDir, hookOptions);\n\n let restoredCount = 0;\n\n for (const file of files) {\n const targetPath = expandPath(file.source);\n\n // Check if source exists in repository\n if (!(await pathExists(file.destination))) {\n logger.warning(`Source not found in repository: ${file.source}`);\n continue;\n }\n\n // Dry run - just show what would happen\n if (options.dryRun) {\n if (file.existsAtTarget) {\n logger.file('modify', `${file.source} (would overwrite)`);\n } else {\n logger.file('add', `${file.source} (would create)`);\n }\n continue;\n }\n\n // Create backup if needed\n if (shouldBackup && file.existsAtTarget) {\n await withSpinner(`Backing up ${file.source}...`, async () => {\n await createBackup(targetPath);\n });\n }\n\n // Restore file\n await withSpinner(`Restoring ${file.source}...`, async () => {\n if (useSymlink) {\n await createSymlink(file.destination, targetPath, { overwrite: true });\n } else {\n await copyFileOrDir(file.destination, targetPath, { overwrite: true });\n }\n\n // Fix permissions for sensitive files\n await fixSSHPermissions(file.source);\n await fixGPGPermissions(file.source);\n });\n\n restoredCount++;\n }\n\n // Run post-restore hook\n await runPostRestoreHook(tuckDir, hookOptions);\n\n return restoredCount;\n};\n\nconst runInteractiveRestore = async (tuckDir: string): Promise<void> => {\n prompts.intro('tuck restore');\n\n // Get all tracked files\n const files = await prepareFilesToRestore(tuckDir);\n\n if (files.length === 0) {\n prompts.log.warning('No files to restore');\n prompts.note(\"Run 'tuck add <path>' to track files first\", 'Tip');\n return;\n }\n\n // Let user select files to restore\n const fileOptions = files.map((file) => {\n const categoryConfig = CATEGORIES[file.category] || { icon: '📄' };\n const status = file.existsAtTarget ? c.yellow('(exists, will backup)') : '';\n\n return {\n value: file.id,\n label: `${categoryConfig.icon} ${file.source} ${status}`,\n hint: file.category,\n };\n });\n\n const selectedIds = await prompts.multiselect('Select files to restore:', fileOptions, {\n required: true,\n });\n\n if (selectedIds.length === 0) {\n prompts.cancel('No files selected');\n return;\n }\n\n const selectedFiles = files.filter((f) => selectedIds.includes(f.id));\n\n // Check for files that exist\n const existingFiles = selectedFiles.filter((f) => f.existsAtTarget);\n if (existingFiles.length > 0) {\n console.log();\n prompts.log.warning(\n `${existingFiles.length} file${existingFiles.length > 1 ? 's' : ''} will be backed up:`\n );\n existingFiles.forEach((f) => console.log(c.dim(` ${f.source}`)));\n console.log();\n }\n\n // Ask about strategy\n const useSymlink = await prompts.select('Restore method:', [\n { value: false, label: 'Copy files', hint: 'Recommended' },\n { value: true, label: 'Create symlinks', hint: 'Files stay in tuck repo' },\n ]);\n\n // Confirm\n const confirm = await prompts.confirm(\n `Restore ${selectedFiles.length} file${selectedFiles.length > 1 ? 's' : ''}?`,\n true\n );\n\n if (!confirm) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n // Restore\n const restoredCount = await restoreFiles(tuckDir, selectedFiles, {\n symlink: useSymlink as boolean,\n backup: true,\n });\n\n console.log();\n prompts.outro(`Restored ${restoredCount} file${restoredCount > 1 ? 's' : ''}`);\n};\n\n/**\n * Run restore programmatically (exported for use by other commands)\n */\nexport const runRestore = async (options: RestoreOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Run interactive restore when called programmatically with --all\n if (options.all) {\n // Prepare files to restore\n const files = await prepareFilesToRestore(tuckDir, undefined);\n\n if (files.length === 0) {\n logger.warning('No files to restore');\n return;\n }\n\n // Restore files with progress\n const restoredCount = await restoreFiles(tuckDir, files, options);\n\n logger.blank();\n logger.success(`Restored ${restoredCount} file${restoredCount > 1 ? 's' : ''}`);\n } else {\n await runInteractiveRestore(tuckDir);\n }\n};\n\nconst runRestoreCommand = async (paths: string[], options: RestoreOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // If no paths and no --all, run interactive\n if (paths.length === 0 && !options.all) {\n await runInteractiveRestore(tuckDir);\n return;\n }\n\n // Prepare files to restore\n const files = await prepareFilesToRestore(tuckDir, options.all ? undefined : paths);\n\n if (files.length === 0) {\n logger.warning('No files to restore');\n return;\n }\n\n // Show what will be restored\n if (options.dryRun) {\n logger.heading('Dry run - would restore:');\n } else {\n logger.heading('Restoring:');\n }\n\n // Restore files\n const restoredCount = await restoreFiles(tuckDir, files, options);\n\n logger.blank();\n\n if (options.dryRun) {\n logger.info(`Would restore ${files.length} file${files.length > 1 ? 's' : ''}`);\n } else {\n logger.success(`Restored ${restoredCount} file${restoredCount > 1 ? 's' : ''}`);\n }\n};\n\nexport const restoreCommand = new Command('restore')\n .description('Restore dotfiles to the system')\n .argument('[paths...]', 'Paths to restore (or use --all)')\n .option('-a, --all', 'Restore all tracked files')\n .option('--symlink', 'Create symlinks instead of copies')\n .option('--backup', 'Backup existing files before restore')\n .option('--no-backup', 'Skip backup of existing files')\n .option('--dry-run', 'Show what would be done')\n .option('--no-hooks', 'Skip execution of pre/post restore hooks')\n .option('--trust-hooks', 'Trust and run hooks without confirmation (use with caution)')\n .action(async (paths: string[], options: RestoreOptions) => {\n await runRestoreCommand(paths, options);\n });\n","import { join } from 'path';\nimport { readFile, writeFile, appendFile } from 'fs/promises';\nimport { pathExists, expandPath, collapsePath } from './paths.js';\n\nconst TUCKIGNORE_FILENAME = '.tuckignore';\n\nconst TUCKIGNORE_HEADER = `# .tuckignore - Files to exclude from tracking\n# One exact file path per line (no globs)\n# Lines starting with # are comments\n#\n# Example:\n# ~/bin/large-binary\n# ~/.docker/config.json\n`;\n\n/**\n * Get the path to .tuckignore file\n */\nexport const getTuckignorePath = (tuckDir: string): string => {\n return join(tuckDir, TUCKIGNORE_FILENAME);\n};\n\n/**\n * Load and parse .tuckignore file\n * Returns a Set of collapsed paths (with ~/ prefix)\n */\nexport const loadTuckignore = async (tuckDir: string): Promise<Set<string>> => {\n const ignorePath = getTuckignorePath(tuckDir);\n const ignoredPaths = new Set<string>();\n\n if (!(await pathExists(ignorePath))) {\n return ignoredPaths;\n }\n\n try {\n const content = await readFile(ignorePath, 'utf-8');\n const lines = content.split('\\n');\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith('#')) {\n continue;\n }\n\n // Expand and then collapse to normalize the path\n const expanded = expandPath(trimmed);\n const collapsed = collapsePath(expanded);\n ignoredPaths.add(collapsed);\n }\n } catch {\n // If the file can't be read, treat it as having no ignore rules.\n // This is intentionally non-fatal as it allows operation when .tuckignore\n // doesn't exist or has permission issues.\n }\n\n return ignoredPaths;\n};\n\n/**\n * Save paths to .tuckignore file\n * Overwrites the entire file\n */\nexport const saveTuckignore = async (tuckDir: string, paths: string[]): Promise<void> => {\n const ignorePath = getTuckignorePath(tuckDir);\n \n // Sort paths for consistent output\n const sortedPaths = [...paths].sort();\n \n const content = TUCKIGNORE_HEADER + '\\n' + sortedPaths.join('\\n') + '\\n';\n \n await writeFile(ignorePath, content, 'utf-8');\n};\n\n/**\n * Add a path to .tuckignore file\n * Appends to the file if it exists, creates it if not\n */\nexport const addToTuckignore = async (tuckDir: string, path: string): Promise<void> => {\n const ignorePath = getTuckignorePath(tuckDir);\n \n // Normalize path to use ~/ prefix\n const expanded = expandPath(path);\n const collapsed = collapsePath(expanded);\n\n // Check if already ignored\n const existingPaths = await loadTuckignore(tuckDir);\n if (existingPaths.has(collapsed)) {\n return; // Already in the ignore file\n }\n\n // If file doesn't exist, create it with header\n if (!(await pathExists(ignorePath))) {\n await writeFile(ignorePath, TUCKIGNORE_HEADER + '\\n', 'utf-8');\n }\n\n // Append the path\n await appendFile(ignorePath, collapsed + '\\n', 'utf-8');\n};\n\n/**\n * Check if a path is in .tuckignore\n */\nexport const isIgnored = async (tuckDir: string, path: string): Promise<boolean> => {\n const ignoredPaths = await loadTuckignore(tuckDir);\n \n // Normalize path for comparison\n const expanded = expandPath(path);\n const collapsed = collapsePath(expanded);\n \n return ignoredPaths.has(collapsed);\n};\n\n/**\n * Remove a path from .tuckignore\n */\nexport const removeFromTuckignore = async (tuckDir: string, path: string): Promise<void> => {\n const ignorePath = getTuckignorePath(tuckDir);\n \n if (!(await pathExists(ignorePath))) {\n return; // Nothing to remove\n }\n\n // Normalize path\n const expanded = expandPath(path);\n const collapsed = collapsePath(expanded);\n\n // Load all paths\n const ignoredPaths = await loadTuckignore(tuckDir);\n ignoredPaths.delete(collapsed);\n\n // Save back\n await saveTuckignore(tuckDir, Array.from(ignoredPaths));\n};\n\n/**\n * Get all ignored paths\n */\nexport const getIgnoredPaths = async (tuckDir: string): Promise<string[]> => {\n const ignoredPaths = await loadTuckignore(tuckDir);\n return Array.from(ignoredPaths).sort();\n};\n\n","/**\n * Secret detection patterns for tuck\n *\n * This module defines regex patterns for detecting various types of secrets\n * including API keys, tokens, private keys, and credentials.\n */\n\nexport type SecretSeverity = 'critical' | 'high' | 'medium' | 'low';\n\nexport interface SecretPattern {\n id: string;\n name: string;\n pattern: RegExp;\n severity: SecretSeverity;\n description: string;\n placeholder: string;\n}\n\n// ============================================================================\n// Cloud Provider Patterns\n// ============================================================================\n\nexport const CLOUD_PROVIDER_PATTERNS: SecretPattern[] = [\n {\n id: 'aws-access-key',\n name: 'AWS Access Key ID',\n pattern: /\\b(AKIA[0-9A-Z]{16})\\b/g,\n severity: 'critical',\n description: 'AWS Access Key ID',\n placeholder: 'AWS_ACCESS_KEY_ID',\n },\n {\n id: 'aws-secret-key',\n name: 'AWS Secret Access Key',\n // AWS secret keys are 40 characters, base64-ish\n // Look for context clues (assignment to aws_secret, etc.)\n pattern: /(?:aws_secret_access_key|aws_secret|secret_access_key)\\s*[=:]\\s*['\"]?([A-Za-z0-9/+=]{40})['\"]?/gi,\n severity: 'critical',\n description: 'AWS Secret Access Key',\n placeholder: 'AWS_SECRET_ACCESS_KEY',\n },\n {\n id: 'aws-session-token',\n name: 'AWS Session Token',\n pattern: /(?:aws_session_token)\\s*[=:]\\s*['\"]?([A-Za-z0-9/+=]{100,1000})['\"]?/gi,\n severity: 'critical',\n description: 'AWS Session Token',\n placeholder: 'AWS_SESSION_TOKEN',\n },\n {\n id: 'gcp-api-key',\n name: 'Google Cloud API Key',\n pattern: /\\b(AIza[0-9A-Za-z_-]{35})\\b/g,\n severity: 'critical',\n description: 'Google Cloud API Key',\n placeholder: 'GCP_API_KEY',\n },\n {\n id: 'gcp-service-account',\n name: 'GCP Service Account',\n // Detects the private_key field in service account JSON\n pattern: /-----BEGIN PRIVATE KEY-----[A-Za-z0-9+/=\\s]+-----END PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'GCP Service Account Private Key',\n placeholder: 'GCP_SERVICE_ACCOUNT_KEY',\n },\n {\n id: 'azure-subscription-key',\n name: 'Azure Subscription Key',\n // Require Azure-specific context (common variable or header names) to reduce false positives.\n // Matches patterns like:\n // const AZURE_SUBSCRIPTION_KEY = \"0123abcd...\"; \n // \"Ocp-Apim-Subscription-Key\": \"0123abcd...\";\n pattern: /\\b(?:azure[_-]?(?:subscription[_-]?key|key)|subscription[_-]?key|Ocp-Apim-Subscription-Key)\\b\\s*[:=]\\s*['\"]?([a-f0-9]{32})['\"]?/gi,\n severity: 'medium', // Lower severity due to remaining false positive risk\n description: 'Azure Subscription Key (with context)',\n placeholder: 'AZURE_SUBSCRIPTION_KEY',\n },\n {\n id: 'digitalocean-token',\n name: 'DigitalOcean Token',\n pattern: /\\b(dop_v1_[a-f0-9]{64})\\b/g,\n severity: 'critical',\n description: 'DigitalOcean Personal Access Token',\n placeholder: 'DIGITALOCEAN_TOKEN',\n },\n {\n id: 'digitalocean-oauth',\n name: 'DigitalOcean OAuth Token',\n pattern: /\\b(doo_v1_[a-f0-9]{64})\\b/g,\n severity: 'critical',\n description: 'DigitalOcean OAuth Token',\n placeholder: 'DIGITALOCEAN_OAUTH_TOKEN',\n },\n {\n id: 'digitalocean-refresh',\n name: 'DigitalOcean Refresh Token',\n pattern: /\\b(dor_v1_[a-f0-9]{64})\\b/g,\n severity: 'critical',\n description: 'DigitalOcean Refresh Token',\n placeholder: 'DIGITALOCEAN_REFRESH_TOKEN',\n },\n];\n\n// ============================================================================\n// API Token Patterns\n// ============================================================================\n\nexport const API_TOKEN_PATTERNS: SecretPattern[] = [\n // GitHub\n {\n id: 'github-pat',\n name: 'GitHub Personal Access Token',\n pattern: /\\b(ghp_[A-Za-z0-9]{36,255})\\b/g,\n severity: 'critical',\n description: 'GitHub Personal Access Token',\n placeholder: 'GITHUB_TOKEN',\n },\n {\n id: 'github-oauth',\n name: 'GitHub OAuth Token',\n pattern: /\\b(gho_[A-Za-z0-9]{36,255})\\b/g,\n severity: 'critical',\n description: 'GitHub OAuth Access Token',\n placeholder: 'GITHUB_OAUTH_TOKEN',\n },\n {\n id: 'github-user-to-server',\n name: 'GitHub User-to-Server Token',\n pattern: /\\b(ghu_[A-Za-z0-9]{36,255})\\b/g,\n severity: 'critical',\n description: 'GitHub User-to-Server Token',\n placeholder: 'GITHUB_USER_TOKEN',\n },\n {\n id: 'github-server-to-server',\n name: 'GitHub Server-to-Server Token',\n pattern: /\\b(ghs_[A-Za-z0-9]{36,255})\\b/g,\n severity: 'critical',\n description: 'GitHub Server-to-Server Token',\n placeholder: 'GITHUB_SERVER_TOKEN',\n },\n {\n id: 'github-refresh',\n name: 'GitHub Refresh Token',\n pattern: /\\b(ghr_[A-Za-z0-9]{36,255})\\b/g,\n severity: 'critical',\n description: 'GitHub Refresh Token',\n placeholder: 'GITHUB_REFRESH_TOKEN',\n },\n {\n id: 'github-fine-grained',\n name: 'GitHub Fine-Grained PAT',\n pattern: /\\b(github_pat_[A-Za-z0-9_]{22,255})\\b/g,\n severity: 'critical',\n description: 'GitHub Fine-Grained Personal Access Token',\n placeholder: 'GITHUB_FINE_GRAINED_TOKEN',\n },\n\n // OpenAI\n {\n id: 'openai-api-key',\n name: 'OpenAI API Key',\n pattern: /\\b(sk-[A-Za-z0-9]{20,256}T3BlbkFJ[A-Za-z0-9]{20,256})\\b/g,\n severity: 'critical',\n description: 'OpenAI API Key (legacy format)',\n placeholder: 'OPENAI_API_KEY',\n },\n {\n id: 'openai-api-key-new',\n name: 'OpenAI API Key (new format)',\n pattern: /\\b(sk-proj-[A-Za-z0-9_-]{80,256})\\b/g,\n severity: 'critical',\n description: 'OpenAI API Key (project format)',\n placeholder: 'OPENAI_API_KEY',\n },\n {\n id: 'openai-api-key-org',\n name: 'OpenAI Organization Key',\n pattern: /\\b(sk-[A-Za-z0-9]{48,256})\\b/g,\n severity: 'critical',\n description: 'OpenAI API Key',\n placeholder: 'OPENAI_API_KEY',\n },\n\n // Anthropic\n {\n id: 'anthropic-api-key',\n name: 'Anthropic API Key',\n pattern: /\\b(sk-ant-api[a-zA-Z0-9_-]{90,256})\\b/g,\n severity: 'critical',\n description: 'Anthropic API Key',\n placeholder: 'ANTHROPIC_API_KEY',\n },\n\n // Slack\n {\n id: 'slack-bot-token',\n name: 'Slack Bot Token',\n pattern: /\\b(xoxb-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*)\\b/g,\n severity: 'critical',\n description: 'Slack Bot Token',\n placeholder: 'SLACK_BOT_TOKEN',\n },\n {\n id: 'slack-user-token',\n name: 'Slack User Token',\n pattern: /\\b(xoxp-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*)\\b/g,\n severity: 'critical',\n description: 'Slack User Token',\n placeholder: 'SLACK_USER_TOKEN',\n },\n {\n id: 'slack-app-token',\n name: 'Slack App Token',\n pattern: /\\b(xapp-[0-9]+-[A-Z0-9]+-[0-9]+-[a-z0-9]+)\\b/gi,\n severity: 'critical',\n description: 'Slack App-Level Token',\n placeholder: 'SLACK_APP_TOKEN',\n },\n {\n id: 'slack-webhook',\n name: 'Slack Webhook URL',\n pattern: /https:\\/\\/hooks\\.slack\\.com\\/services\\/T[A-Z0-9]+\\/B[A-Z0-9]+\\/[a-zA-Z0-9]+/g,\n severity: 'high',\n description: 'Slack Incoming Webhook URL',\n placeholder: 'SLACK_WEBHOOK_URL',\n },\n\n // Stripe\n {\n id: 'stripe-live-secret',\n name: 'Stripe Live Secret Key',\n pattern: /\\b(sk_live_[0-9a-zA-Z]{24,256})\\b/g,\n severity: 'critical',\n description: 'Stripe Live Secret Key',\n placeholder: 'STRIPE_SECRET_KEY',\n },\n {\n id: 'stripe-live-publishable',\n name: 'Stripe Live Publishable Key',\n pattern: /\\b(pk_live_[0-9a-zA-Z]{24,256})\\b/g,\n severity: 'high',\n description: 'Stripe Live Publishable Key',\n placeholder: 'STRIPE_PUBLISHABLE_KEY',\n },\n {\n id: 'stripe-test-secret',\n name: 'Stripe Test Secret Key',\n pattern: /\\b(sk_test_[0-9a-zA-Z]{24,256})\\b/g,\n severity: 'medium',\n description: 'Stripe Test Secret Key',\n placeholder: 'STRIPE_TEST_SECRET_KEY',\n },\n {\n id: 'stripe-restricted',\n name: 'Stripe Restricted Key',\n pattern: /\\b(rk_live_[0-9a-zA-Z]{24,256})\\b/g,\n severity: 'critical',\n description: 'Stripe Restricted API Key',\n placeholder: 'STRIPE_RESTRICTED_KEY',\n },\n\n // Twilio\n {\n id: 'twilio-api-key',\n name: 'Twilio API Key',\n pattern: /\\b(SK[0-9a-fA-F]{32})\\b/g,\n severity: 'critical',\n description: 'Twilio API Key',\n placeholder: 'TWILIO_API_KEY',\n },\n {\n id: 'twilio-account-sid',\n name: 'Twilio Account SID',\n pattern: /\\b(AC[0-9a-fA-F]{32})\\b/g,\n severity: 'high',\n description: 'Twilio Account SID',\n placeholder: 'TWILIO_ACCOUNT_SID',\n },\n\n // SendGrid\n {\n id: 'sendgrid-api-key',\n name: 'SendGrid API Key',\n pattern: /\\b(SG\\.[A-Za-z0-9_-]{22}\\.[A-Za-z0-9_-]{43})\\b/g,\n severity: 'critical',\n description: 'SendGrid API Key',\n placeholder: 'SENDGRID_API_KEY',\n },\n\n // Mailchimp\n {\n id: 'mailchimp-api-key',\n name: 'Mailchimp API Key',\n pattern: /\\b([a-f0-9]{32}-us[0-9]{1,2})\\b/g,\n severity: 'critical',\n description: 'Mailchimp API Key',\n placeholder: 'MAILCHIMP_API_KEY',\n },\n\n // npm\n {\n id: 'npm-access-token',\n name: 'npm Access Token',\n pattern: /\\b(npm_[A-Za-z0-9]{36})\\b/g,\n severity: 'critical',\n description: 'npm Access Token',\n placeholder: 'NPM_TOKEN',\n },\n\n // PyPI\n {\n id: 'pypi-api-token',\n name: 'PyPI API Token',\n pattern: /\\b(pypi-AgEIcHlwaS5vcmc[A-Za-z0-9_-]{50,256})\\b/g,\n severity: 'critical',\n description: 'PyPI API Token',\n placeholder: 'PYPI_TOKEN',\n },\n\n // Discord\n {\n id: 'discord-bot-token',\n name: 'Discord Bot Token',\n pattern: /\\b([MN][A-Za-z\\d]{23,256}\\.[\\w-]{6}\\.[\\w-]{27})\\b/g,\n severity: 'critical',\n description: 'Discord Bot Token',\n placeholder: 'DISCORD_BOT_TOKEN',\n },\n {\n id: 'discord-webhook',\n name: 'Discord Webhook URL',\n pattern: /https:\\/\\/discord(?:app)?\\.com\\/api\\/webhooks\\/[0-9]+\\/[A-Za-z0-9_-]+/g,\n severity: 'high',\n description: 'Discord Webhook URL',\n placeholder: 'DISCORD_WEBHOOK_URL',\n },\n\n // Telegram\n {\n id: 'telegram-bot-token',\n name: 'Telegram Bot Token',\n pattern: /\\b([0-9]{8,10}:[A-Za-z0-9_-]{35})\\b/g,\n severity: 'critical',\n description: 'Telegram Bot API Token',\n placeholder: 'TELEGRAM_BOT_TOKEN',\n },\n\n // Heroku\n {\n id: 'heroku-api-key',\n name: 'Heroku API Key',\n // Require Heroku-specific context to reduce UUID false positives\n pattern: /\\b(?:heroku[_-]?(?:api[_-]?key|key|token)|HEROKU_API_KEY)\\b\\s*[:=]\\s*['\"]?([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})['\"]?/gi,\n severity: 'high',\n description: 'Heroku API Key (UUID format with context)',\n placeholder: 'HEROKU_API_KEY',\n },\n\n // Datadog\n {\n id: 'datadog-api-key',\n name: 'Datadog API Key',\n // Require Datadog-specific context to reduce false positives\n pattern: /\\b(?:datadog[_-]?(?:api[_-]?key|key)|DD_API_KEY)\\b\\s*[:=]\\s*['\"]?([a-f0-9]{32})['\"]?/gi,\n severity: 'medium', // Lower due to false positives\n description: 'Datadog API Key (with context)',\n placeholder: 'DATADOG_API_KEY',\n },\n\n // CircleCI\n {\n id: 'circleci-token',\n name: 'CircleCI Personal Token',\n pattern: /\\b(circle-token-[a-f0-9]{40})\\b/g,\n severity: 'critical',\n description: 'CircleCI Personal API Token',\n placeholder: 'CIRCLECI_TOKEN',\n },\n\n // Travis CI\n {\n id: 'travis-token',\n name: 'Travis CI Token',\n // Require Travis-specific context to reduce false positives\n pattern: /\\b(?:travis[_-]?(?:token|key|api[_-]?key)|TRAVIS_TOKEN)\\b\\s*[:=]\\s*['\"]?([a-zA-Z0-9]{22})['\"]?/gi,\n severity: 'medium', // Lower due to false positives\n description: 'Travis CI Access Token (with context)',\n placeholder: 'TRAVIS_TOKEN',\n },\n\n // Firebase\n {\n id: 'firebase-api-key',\n name: 'Firebase API Key',\n pattern: /\\b(AIza[0-9A-Za-z_-]{35})\\b/g,\n severity: 'high',\n description: 'Firebase/Google API Key',\n placeholder: 'FIREBASE_API_KEY',\n },\n\n // Supabase\n {\n id: 'supabase-anon-key',\n name: 'Supabase Anon Key',\n pattern: /\\b(eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+)\\b/g,\n severity: 'high',\n description: 'Supabase Anonymous Key (JWT)',\n placeholder: 'SUPABASE_ANON_KEY',\n },\n\n // Vercel\n {\n id: 'vercel-token',\n name: 'Vercel Token',\n // Require Vercel-specific context to reduce false positives\n pattern: /\\b(?:vercel[_-]?(?:token|key)|VERCEL_TOKEN)\\b\\s*[:=]\\s*['\"]?([A-Za-z0-9]{24})['\"]?/gi,\n severity: 'medium', // Lower due to false positives\n description: 'Vercel Access Token (with context)',\n placeholder: 'VERCEL_TOKEN',\n },\n\n // Netlify\n {\n id: 'netlify-token',\n name: 'Netlify Personal Access Token',\n pattern: /\\b(nfp_[A-Za-z0-9]{40})\\b/g,\n severity: 'critical',\n description: 'Netlify Personal Access Token',\n placeholder: 'NETLIFY_TOKEN',\n },\n];\n\n// ============================================================================\n// Private Key Patterns\n// ============================================================================\n\nexport const PRIVATE_KEY_PATTERNS: SecretPattern[] = [\n {\n id: 'rsa-private-key',\n name: 'RSA Private Key',\n // Security: Length limit to prevent ReDoS\n pattern: /-----BEGIN RSA PRIVATE KEY-----[\\s\\S]{1,10000}?-----END RSA PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'RSA Private Key',\n placeholder: 'RSA_PRIVATE_KEY',\n },\n {\n id: 'openssh-private-key',\n name: 'OpenSSH Private Key',\n pattern: /-----BEGIN OPENSSH PRIVATE KEY-----[\\s\\S]{1,10000}?-----END OPENSSH PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'OpenSSH Private Key',\n placeholder: 'SSH_PRIVATE_KEY',\n },\n {\n id: 'dsa-private-key',\n name: 'DSA Private Key',\n pattern: /-----BEGIN DSA PRIVATE KEY-----[\\s\\S]{1,10000}?-----END DSA PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'DSA Private Key',\n placeholder: 'DSA_PRIVATE_KEY',\n },\n {\n id: 'ec-private-key',\n name: 'EC Private Key',\n pattern: /-----BEGIN EC PRIVATE KEY-----[\\s\\S]{1,10000}?-----END EC PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'EC Private Key',\n placeholder: 'EC_PRIVATE_KEY',\n },\n {\n id: 'generic-private-key',\n name: 'Generic Private Key',\n pattern: /-----BEGIN PRIVATE KEY-----[\\s\\S]{1,10000}?-----END PRIVATE KEY-----/g,\n severity: 'critical',\n description: 'PKCS#8 Private Key',\n placeholder: 'PRIVATE_KEY',\n },\n {\n id: 'encrypted-private-key',\n name: 'Encrypted Private Key',\n pattern: /-----BEGIN ENCRYPTED PRIVATE KEY-----[\\s\\S]{1,10000}?-----END ENCRYPTED PRIVATE KEY-----/g,\n severity: 'high',\n description: 'Encrypted Private Key',\n placeholder: 'ENCRYPTED_PRIVATE_KEY',\n },\n {\n id: 'pgp-private-key',\n name: 'PGP Private Key',\n pattern: /-----BEGIN PGP PRIVATE KEY BLOCK-----[\\s\\S]{1,10000}?-----END PGP PRIVATE KEY BLOCK-----/g,\n severity: 'critical',\n description: 'PGP Private Key Block',\n placeholder: 'PGP_PRIVATE_KEY',\n },\n {\n id: 'putty-private-key',\n name: 'PuTTY Private Key',\n // Security: Length limit to prevent ReDoS\n pattern: /PuTTY-User-Key-File-[0-9]+:[\\s\\S]{1,5000}?Private-Lines:/g,\n severity: 'critical',\n description: 'PuTTY Private Key',\n placeholder: 'PUTTY_PRIVATE_KEY',\n },\n];\n\n// ============================================================================\n// Generic Secret Patterns\n// ============================================================================\n\nexport const GENERIC_PATTERNS: SecretPattern[] = [\n // Password assignments\n {\n id: 'password-assignment',\n name: 'Password Assignment',\n // Security: Upper bound to prevent ReDoS\n pattern: /(?:password|passwd|pwd|pass)\\s*[=:]\\s*['\"]([^'\"]{8,200})['\"]?/gi,\n severity: 'high',\n description: 'Password assigned in configuration',\n placeholder: 'PASSWORD',\n },\n {\n id: 'password-url',\n name: 'Password in URL',\n // Security: Upper bounds to prevent ReDoS\n pattern: /:\\/\\/[^:]{1,100}:([^@]{8,200})@/g,\n severity: 'critical',\n description: 'Password embedded in URL',\n placeholder: 'URL_PASSWORD',\n },\n\n // API key assignments\n {\n id: 'api-key-assignment',\n name: 'API Key Assignment',\n pattern: /(?:api[_-]?key|apikey)\\s*[=:]\\s*(?:['\"]([A-Za-z0-9_-]{16,256})['\"]|([A-Za-z0-9_-]{16,256}))/gi,\n severity: 'high',\n description: 'API key assigned in configuration',\n placeholder: 'API_KEY',\n },\n\n // Token assignments\n {\n id: 'token-assignment',\n name: 'Token Assignment',\n pattern: /(?:token|auth[_-]?token|access[_-]?token|bearer[_-]?token)\\s*[=:]\\s*(?:['\"]([A-Za-z0-9_.-]{20,256})['\"]|([A-Za-z0-9_.-]{20,256}))/gi,\n severity: 'high',\n description: 'Token assigned in configuration',\n placeholder: 'TOKEN',\n },\n\n // Secret assignments\n {\n id: 'secret-assignment',\n name: 'Secret Assignment',\n pattern: /(?:secret|client[_-]?secret|app[_-]?secret|secret[_-]?key)\\s*[=:]\\s*(?:['\"]([A-Za-z0-9_-]{16,256})['\"]|([A-Za-z0-9_-]{16,256}))/gi,\n severity: 'high',\n description: 'Secret assigned in configuration',\n placeholder: 'SECRET',\n },\n\n // Bearer tokens\n {\n id: 'bearer-token',\n name: 'Bearer Token',\n pattern: /Bearer\\s+([A-Za-z0-9_.-]{20,256})/g,\n severity: 'high',\n description: 'Bearer authentication token',\n placeholder: 'BEARER_TOKEN',\n },\n\n // Basic auth\n {\n id: 'basic-auth-header',\n name: 'Basic Auth Header',\n pattern: /Basic\\s+([A-Za-z0-9+/=]{20,256})/g,\n severity: 'high',\n description: 'Base64 encoded credentials',\n placeholder: 'BASIC_AUTH',\n },\n\n // Database connection strings\n // Security: All patterns have length limits to prevent ReDoS\n {\n id: 'postgres-connection',\n name: 'PostgreSQL Connection String',\n pattern: /postgres(?:ql)?:\\/\\/[^:]{1,100}:[^@]{1,200}@[^\\s'\"]{1,500}/gi,\n severity: 'critical',\n description: 'PostgreSQL connection string with credentials',\n placeholder: 'DATABASE_URL',\n },\n {\n id: 'mysql-connection',\n name: 'MySQL Connection String',\n pattern: /mysql:\\/\\/[^:]{1,100}:[^@]{1,200}@[^\\s'\"]{1,500}/gi,\n severity: 'critical',\n description: 'MySQL connection string with credentials',\n placeholder: 'DATABASE_URL',\n },\n {\n id: 'mongodb-connection',\n name: 'MongoDB Connection String',\n pattern: /mongodb(?:\\+srv)?:\\/\\/[^:]{1,100}:[^@]{1,200}@[^\\s'\"]{1,500}/gi,\n severity: 'critical',\n description: 'MongoDB connection string with credentials',\n placeholder: 'MONGODB_URI',\n },\n {\n id: 'redis-connection',\n name: 'Redis Connection String',\n pattern: /redis:\\/\\/[^:]{1,100}:[^@]{1,200}@[^\\s'\"]{1,500}/gi,\n severity: 'critical',\n description: 'Redis connection string with credentials',\n placeholder: 'REDIS_URL',\n },\n\n // JWT tokens (generic)\n {\n id: 'jwt-token',\n name: 'JWT Token',\n pattern: /\\beyJ[A-Za-z0-9_-]{10,256}\\.[A-Za-z0-9_-]{10,256}\\.[A-Za-z0-9_-]{10,256}\\b/g,\n severity: 'high',\n description: 'JSON Web Token',\n placeholder: 'JWT_TOKEN',\n },\n\n // Private key content (partial detection)\n {\n id: 'base64-private-key',\n name: 'Base64 Private Key Content',\n pattern: /MII[A-Za-z0-9+/]{60,512}={0,2}/g,\n severity: 'high',\n description: 'Base64 encoded private key content',\n placeholder: 'PRIVATE_KEY_CONTENT',\n },\n\n // Encryption keys\n {\n id: 'encryption-key',\n name: 'Encryption Key',\n pattern: /(?:encryption[_-]?key|aes[_-]?key|crypto[_-]?key)\\s*[=:]\\s*['\"]?([A-Fa-f0-9]{32,256})['\"]?/gi,\n severity: 'critical',\n description: 'Encryption key',\n placeholder: 'ENCRYPTION_KEY',\n },\n\n // SSH passphrase\n {\n id: 'ssh-passphrase',\n name: 'SSH Passphrase',\n pattern: /(?:ssh[_-]?passphrase|key[_-]?passphrase)\\s*[=:]\\s*['\"]([^'\"]+)['\"]?/gi,\n severity: 'critical',\n description: 'SSH key passphrase',\n placeholder: 'SSH_PASSPHRASE',\n },\n];\n\n// ============================================================================\n// Combine All Patterns\n// ============================================================================\n\nexport const ALL_SECRET_PATTERNS: SecretPattern[] = [\n ...CLOUD_PROVIDER_PATTERNS,\n ...API_TOKEN_PATTERNS,\n ...PRIVATE_KEY_PATTERNS,\n ...GENERIC_PATTERNS,\n];\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get patterns by severity level\n */\nexport const getPatternsBySeverity = (severity: SecretSeverity): SecretPattern[] => {\n return ALL_SECRET_PATTERNS.filter((p) => p.severity === severity);\n};\n\n/**\n * Get pattern by ID\n */\nexport const getPatternById = (id: string): SecretPattern | undefined => {\n return ALL_SECRET_PATTERNS.find((p) => p.id === id);\n};\n\n/**\n * Get patterns above a minimum severity\n * (critical > high > medium > low)\n */\nexport const getPatternsAboveSeverity = (minSeverity: SecretSeverity): SecretPattern[] => {\n const severityOrder: Record<SecretSeverity, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n };\n\n const minLevel = severityOrder[minSeverity];\n return ALL_SECRET_PATTERNS.filter((p) => severityOrder[p.severity] <= minLevel);\n};\n\n/**\n * Create a custom pattern\n */\nexport const createCustomPattern = (\n id: string,\n name: string,\n pattern: string,\n options?: {\n severity?: SecretSeverity;\n description?: string;\n placeholder?: string;\n flags?: string;\n }\n): SecretPattern => {\n return {\n id: `custom-${id}`,\n name,\n pattern: new RegExp(pattern, options?.flags || 'g'),\n severity: options?.severity || 'high',\n description: options?.description || `Custom pattern: ${name}`,\n placeholder: options?.placeholder || id.toUpperCase().replace(/-/g, '_'),\n };\n};\n\n/**\n * Binary file extensions that should be skipped during scanning\n */\nexport const BINARY_EXTENSIONS = new Set([\n // Images\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.bmp',\n '.ico',\n '.webp',\n '.svg',\n '.tiff',\n '.tif',\n // Documents\n '.pdf',\n '.doc',\n '.docx',\n '.xls',\n '.xlsx',\n '.ppt',\n '.pptx',\n // Archives\n '.zip',\n '.tar',\n '.gz',\n '.bz2',\n '.7z',\n '.rar',\n '.xz',\n // Binaries\n '.exe',\n '.dll',\n '.so',\n '.dylib',\n '.bin',\n '.o',\n '.a',\n // Fonts\n '.ttf',\n '.otf',\n '.woff',\n '.woff2',\n '.eot',\n // Media\n '.mp3',\n '.mp4',\n '.wav',\n '.avi',\n '.mov',\n '.mkv',\n '.flac',\n // Database\n '.db',\n '.sqlite',\n '.sqlite3',\n // Other\n '.pyc',\n '.pyo',\n '.class',\n '.jar',\n]);\n\n/**\n * Check if a file should be skipped based on extension\n * Note: For files with multiple dots (e.g., archive.tar.gz), only the final extension (.gz) is checked\n */\nexport const shouldSkipFile = (filepath: string): boolean => {\n const lastDotIndex = filepath.lastIndexOf('.');\n if (lastDotIndex === -1 || lastDotIndex === filepath.length - 1) {\n // No extension or dot is at the end\n return false;\n }\n const ext = filepath.slice(lastDotIndex).toLowerCase();\n return BINARY_EXTENSIONS.has(ext);\n};\n","/**\n * Secret scanning engine for tuck\n *\n * Provides functions to scan file content for secrets using pattern matching.\n */\n\nimport { readFile, stat } from 'fs/promises';\nimport { expandPath, collapsePath, pathExists } from '../paths.js';\nimport {\n ALL_SECRET_PATTERNS,\n getPatternsAboveSeverity,\n shouldSkipFile,\n type SecretPattern,\n type SecretSeverity,\n} from './patterns.js';\n\n// Maximum file size to scan (10MB)\nconst MAX_FILE_SIZE = 10 * 1024 * 1024;\n\n// Security: File count limits to prevent resource exhaustion\nconst MAX_FILES_PER_SCAN = 1000; // Hard limit on files per scan\nconst WARN_FILES_THRESHOLD = 100; // Warn user when scanning many files\n\n// Security: Timeout protection to prevent DoS from pathological patterns\nconst SCAN_TIMEOUT_MS = 30000; // 30 seconds max for entire content scan\nconst PATTERN_TIMEOUT_MS = 5000; // 5 seconds max per pattern\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SecretMatch {\n patternId: string;\n patternName: string;\n severity: SecretSeverity;\n value: string;\n redactedValue: string;\n line: number;\n column: number;\n context: string;\n placeholder: string;\n}\n\nexport interface FileScanResult {\n path: string;\n collapsedPath: string;\n hasSecrets: boolean;\n matches: SecretMatch[];\n criticalCount: number;\n highCount: number;\n mediumCount: number;\n lowCount: number;\n skipped: boolean;\n skipReason?: string;\n}\n\nexport interface ScanOptions {\n patterns?: SecretPattern[];\n customPatterns?: SecretPattern[];\n excludePatternIds?: string[];\n minSeverity?: SecretSeverity;\n maxFileSize?: number;\n}\n\nexport interface ScanSummary {\n totalFiles: number;\n scannedFiles: number;\n skippedFiles: number;\n filesWithSecrets: number;\n totalSecrets: number;\n bySeverity: {\n critical: number;\n high: number;\n medium: number;\n low: number;\n };\n results: FileScanResult[];\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Redact a secret value for display\n * Security: NEVER show any actual characters from the secret to prevent information leakage.\n * Only show length indicators and type hints.\n */\nexport const redactSecret = (value: string): string => {\n // For multiline values (like private keys), show type hint only\n if (value.includes('\\n')) {\n const firstLine = value.split('\\n')[0];\n if (firstLine.startsWith('-----BEGIN')) {\n // Show only the header type, no actual content\n return firstLine + '\\n[REDACTED - Private Key]';\n }\n return '[REDACTED MULTILINE SECRET]';\n }\n\n // Security: Never show any actual characters from the secret\n // Only show length indicator to help identify which secret it is\n if (value.length <= 20) {\n return '[REDACTED]';\n } else if (value.length <= 50) {\n return '[REDACTED SECRET]';\n } else {\n return '[REDACTED LONG SECRET]';\n }\n};\n\n/**\n * Get line and column number from string index\n */\nconst getPosition = (content: string, index: number): { line: number; column: number } => {\n const beforeMatch = content.slice(0, index);\n const lines = beforeMatch.split('\\n');\n return {\n line: lines.length,\n column: lines[lines.length - 1].length + 1,\n };\n};\n\n/**\n * Get the line containing the match with secret redacted\n * Security: Ensures the secret is always fully redacted in the context,\n * with fallback to fully redacting the line if replacement fails.\n */\nconst getContext = (content: string, lineNum: number, secretValue: string): string => {\n const lines = content.split('\\n');\n const line = lines[lineNum - 1] || '';\n\n try {\n // Redact the secret in the context\n let contextLine: string;\n const secretToFind = secretValue.includes('\\n') ? secretValue.split('\\n')[0] : secretValue;\n\n // Security: Escape regex special characters in secret value\n const escaped = secretToFind.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regex = new RegExp(escaped, 'g');\n contextLine = line.replace(regex, '[REDACTED]');\n\n // Security: If the replacement didn't change the line but it might contain part of the secret,\n // fully redact the line to prevent any potential leakage\n if (contextLine === line && secretToFind.length > 4) {\n // Check if any significant portion of the secret might be in the line\n const partialSecret = secretToFind.slice(0, Math.min(8, secretToFind.length));\n if (line.includes(partialSecret)) {\n return '[Line contains secret - REDACTED]';\n }\n }\n\n // Truncate long lines\n if (contextLine.length > 100) {\n contextLine = contextLine.slice(0, 97) + '...';\n }\n\n return contextLine.trim();\n } catch {\n // Security: On any error, return fully redacted context\n return '[Context redacted for security]';\n }\n};\n\n/**\n * Clone a regex pattern to reset its lastIndex\n */\nconst clonePattern = (pattern: RegExp): RegExp => {\n return new RegExp(pattern.source, pattern.flags);\n};\n\n// ============================================================================\n// Core Scanning Functions\n// ============================================================================\n\n/**\n * Scan content string for secrets\n */\nexport const scanContent = (content: string, options: ScanOptions = {}): SecretMatch[] => {\n const matches: SecretMatch[] = [];\n const seenMatches = new Set<string>(); // Deduplicate matches\n\n // Security: Track scan start time for timeout protection\n const scanStartTime = Date.now();\n\n // Determine which patterns to use\n let patterns: SecretPattern[];\n\n if (options.patterns) {\n patterns = options.patterns;\n } else if (options.minSeverity) {\n patterns = getPatternsAboveSeverity(options.minSeverity);\n } else {\n patterns = ALL_SECRET_PATTERNS;\n }\n\n // Add custom patterns\n if (options.customPatterns) {\n patterns = [...patterns, ...options.customPatterns];\n }\n\n // Exclude specific pattern IDs\n if (options.excludePatternIds && options.excludePatternIds.length > 0) {\n const excludeSet = new Set(options.excludePatternIds);\n patterns = patterns.filter((p) => !excludeSet.has(p.id));\n }\n\n // Scan with each pattern\n for (const pattern of patterns) {\n // Security: Check total scan timeout\n if (Date.now() - scanStartTime > SCAN_TIMEOUT_MS) {\n console.warn('[tuck] Warning: Scan timeout reached, some patterns may not have been checked');\n break;\n }\n\n // Clone the pattern to reset lastIndex\n const regex = clonePattern(pattern.pattern);\n\n // Security: Track pattern start time\n const patternStartTime = Date.now();\n\n let match: RegExpExecArray | null;\n while ((match = regex.exec(content)) !== null) {\n // Security: Check pattern timeout to prevent ReDoS\n if (Date.now() - patternStartTime > PATTERN_TIMEOUT_MS) {\n console.warn(`[tuck] Warning: Pattern ${pattern.id} timed out, skipping remaining matches`);\n break;\n }\n\n // Extract the captured value (prefer capture group 1 if exists)\n const value = match[1] || match[0];\n\n // Skip empty or very short matches\n if (!value || value.length < 4) {\n continue;\n }\n\n // Create unique key for deduplication\n const matchKey = `${pattern.id}:${match.index}:${value.length}`;\n if (seenMatches.has(matchKey)) {\n continue;\n }\n seenMatches.add(matchKey);\n\n const position = getPosition(content, match.index);\n\n matches.push({\n patternId: pattern.id,\n patternName: pattern.name,\n severity: pattern.severity,\n value,\n redactedValue: redactSecret(value),\n line: position.line,\n column: position.column,\n context: getContext(content, position.line, value),\n placeholder: pattern.placeholder,\n });\n\n // Prevent infinite loops for zero-width matches\n if (match.index === regex.lastIndex) {\n regex.lastIndex++;\n }\n }\n }\n\n // Sort by line number, then column\n matches.sort((a, b) => {\n if (a.line !== b.line) return a.line - b.line;\n return a.column - b.column;\n });\n\n return matches;\n};\n\n/**\n * Scan a single file for secrets\n */\nexport const scanFile = async (filepath: string, options: ScanOptions = {}): Promise<FileScanResult> => {\n const expandedPath = expandPath(filepath);\n const collapsedPath = collapsePath(expandedPath);\n const maxSize = options.maxFileSize || MAX_FILE_SIZE;\n\n // Check if file exists\n if (!(await pathExists(expandedPath))) {\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: 'File not found',\n };\n }\n\n // Check if it's a binary file by extension\n if (shouldSkipFile(expandedPath)) {\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: 'Binary file',\n };\n }\n\n // Check file size\n try {\n const stats = await stat(expandedPath);\n if (stats.size > maxSize) {\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: `File too large (${Math.round(stats.size / 1024 / 1024)}MB > ${Math.round(maxSize / 1024 / 1024)}MB)`,\n };\n }\n\n // Skip directories\n if (stats.isDirectory()) {\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: 'Is a directory',\n };\n }\n } catch {\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: 'Cannot read file stats',\n };\n }\n\n // Read and scan file content\n try {\n const content = await readFile(expandedPath, 'utf-8');\n const matches = scanContent(content, options);\n\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: matches.length > 0,\n matches,\n criticalCount: matches.filter((m) => m.severity === 'critical').length,\n highCount: matches.filter((m) => m.severity === 'high').length,\n mediumCount: matches.filter((m) => m.severity === 'medium').length,\n lowCount: matches.filter((m) => m.severity === 'low').length,\n skipped: false,\n };\n } catch (error) {\n // Handle encoding errors (likely binary content)\n return {\n path: expandedPath,\n collapsedPath,\n hasSecrets: false,\n matches: [],\n criticalCount: 0,\n highCount: 0,\n mediumCount: 0,\n lowCount: 0,\n skipped: true,\n skipReason: 'Cannot read file (possibly binary)',\n };\n }\n};\n\n/**\n * Scan multiple files for secrets\n */\nexport const scanFiles = async (filepaths: string[], options: ScanOptions = {}): Promise<ScanSummary> => {\n // Security: Check file count limits to prevent resource exhaustion\n if (filepaths.length > MAX_FILES_PER_SCAN) {\n throw new Error(\n `Too many files to scan (${filepaths.length} > ${MAX_FILES_PER_SCAN}). ` +\n 'Please scan in smaller batches or use --exclude patterns to reduce scan scope.'\n );\n }\n\n if (filepaths.length > WARN_FILES_THRESHOLD) {\n console.warn(\n `[tuck] Warning: Scanning ${filepaths.length} files may take a while. ` +\n 'Consider using --exclude patterns to reduce scan scope if this is slow.'\n );\n }\n\n const results: FileScanResult[] = [];\n\n // Scan files in parallel batches (with concurrency limit)\n const CONCURRENCY = 10;\n for (let i = 0; i < filepaths.length; i += CONCURRENCY) {\n const batch = filepaths.slice(i, i + CONCURRENCY);\n const batchResults = await Promise.all(batch.map((path) => scanFile(path, options)));\n results.push(...batchResults);\n }\n\n // Build summary\n const summary: ScanSummary = {\n totalFiles: filepaths.length,\n scannedFiles: results.filter((r) => !r.skipped).length,\n skippedFiles: results.filter((r) => r.skipped).length,\n filesWithSecrets: results.filter((r) => r.hasSecrets).length,\n totalSecrets: 0,\n bySeverity: { critical: 0, high: 0, medium: 0, low: 0 },\n results: results.filter((r) => r.hasSecrets), // Only include files with secrets\n };\n\n for (const result of results) {\n summary.totalSecrets += result.matches.length;\n summary.bySeverity.critical += result.criticalCount;\n summary.bySeverity.high += result.highCount;\n summary.bySeverity.medium += result.mediumCount;\n summary.bySeverity.low += result.lowCount;\n }\n\n return summary;\n};\n\n/**\n * Generate unique placeholder names when there are duplicates\n */\nexport const generateUniquePlaceholder = (\n basePlaceholder: string,\n existingPlaceholders: Set<string>,\n hint?: string\n): string => {\n let placeholder = basePlaceholder;\n\n // Add hint to make it more descriptive\n if (hint) {\n const sanitizedHint = hint.toUpperCase().replace(/[^A-Z0-9]/g, '_');\n placeholder = `${basePlaceholder}_${sanitizedHint}`;\n }\n\n // Ensure uniqueness\n if (!existingPlaceholders.has(placeholder)) {\n existingPlaceholders.add(placeholder);\n return placeholder;\n }\n\n // Add numeric suffix\n let counter = 1;\n while (existingPlaceholders.has(`${placeholder}_${counter}`)) {\n counter++;\n }\n\n const uniquePlaceholder = `${placeholder}_${counter}`;\n existingPlaceholders.add(uniquePlaceholder);\n return uniquePlaceholder;\n};\n\n/**\n * Get all unique secret values from scan results with their placeholders\n */\nexport const getSecretsWithPlaceholders = (\n results: FileScanResult[]\n): Map<string, { placeholder: string; pattern: string; severity: SecretSeverity }> => {\n const secrets = new Map<string, { placeholder: string; pattern: string; severity: SecretSeverity }>();\n const usedPlaceholders = new Set<string>();\n\n for (const result of results) {\n for (const match of result.matches) {\n // Skip if we already have this exact secret value\n if (secrets.has(match.value)) {\n continue;\n }\n\n // Generate unique placeholder\n const placeholder = generateUniquePlaceholder(match.placeholder, usedPlaceholders);\n\n secrets.set(match.value, {\n placeholder,\n pattern: match.patternName,\n severity: match.severity,\n });\n }\n }\n\n return secrets;\n};\n","/**\n * Local secrets store management for tuck\n *\n * Manages the secrets.local.json file which stores actual secret values\n * locally (never committed to git). These values are used to replace\n * placeholders in dotfiles.\n */\n\nimport { readFile, writeFile, chmod, stat } from 'fs/promises';\nimport { join } from 'path';\nimport { ensureDir } from 'fs-extra';\nimport { pathExists } from '../paths.js';\nimport { secretsStoreSchema, type SecretsStore } from '../../schemas/secrets.schema.js';\n\n// File permission constants\nconst SECRETS_FILE_MODE = 0o600; // Owner read/write only (rw-------)\nconst TUCK_DIR_MODE = 0o700; // Owner read/write/execute only (rwx------)\n\nconst SECRETS_FILENAME = 'secrets.local.json';\n\n// ============================================================================\n// Path Helpers\n// ============================================================================\n\n/**\n * Get the path to the secrets file\n */\nexport const getSecretsPath = (tuckDir: string): string => {\n return join(tuckDir, SECRETS_FILENAME);\n};\n\n// ============================================================================\n// Store Operations\n// ============================================================================\n\n/**\n * Load the secrets store from disk\n */\nexport const loadSecretsStore = async (tuckDir: string): Promise<SecretsStore> => {\n const secretsPath = getSecretsPath(tuckDir);\n\n if (!(await pathExists(secretsPath))) {\n return {\n version: '1.0.0',\n secrets: {},\n };\n }\n\n // Security: Check and fix file permissions if too permissive\n try {\n const stats = await stat(secretsPath);\n const mode = stats.mode & 0o777;\n // If group or other have any permissions, fix it\n if ((mode & 0o077) !== 0) {\n await chmod(secretsPath, SECRETS_FILE_MODE);\n }\n } catch {\n // Ignore permission check errors (might be Windows)\n }\n\n try {\n const content = await readFile(secretsPath, 'utf-8');\n const parsed = JSON.parse(content);\n return secretsStoreSchema.parse(parsed);\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n\n // If the file disappeared between the existence check and read, treat as \"no secrets yet\"\n if (typeof error === 'object' && error !== null && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n console.warn(\n `[tuck] Warning: Secrets store file not found when reading at '${secretsPath}': ${errorMsg}`\n );\n return {\n version: '1.0.0',\n secrets: {},\n };\n }\n\n // For any other error (permissions, corruption, validation issues), surface a clear failure\n console.error(\n `[tuck] Error: Failed to load secrets store from '${secretsPath}': ${errorMsg}`\n );\n throw new Error(\n `[tuck] Failed to load secrets store from '${secretsPath}': ${errorMsg}`\n );\n }\n};\n\n// Track if we've warned about Windows permissions (only warn once per session)\nlet windowsPermissionWarningShown = false;\n\n/**\n * Save the secrets store to disk with secure permissions\n */\nexport const saveSecretsStore = async (tuckDir: string, store: SecretsStore): Promise<void> => {\n const secretsPath = getSecretsPath(tuckDir);\n await ensureDir(tuckDir);\n\n // Security: Set directory permissions to owner-only\n try {\n await chmod(tuckDir, TUCK_DIR_MODE);\n } catch {\n // chmod not supported (Windows) - permissions handled differently\n }\n\n const content = JSON.stringify(store, null, 2) + '\\n';\n await writeFile(secretsPath, content, 'utf-8');\n\n // Security: Set file permissions to owner read/write only (0600)\n try {\n await chmod(secretsPath, SECRETS_FILE_MODE);\n } catch {\n // Security: Warn Windows users about permission limitations (once per session)\n if (process.platform === 'win32' && !windowsPermissionWarningShown) {\n console.warn(\n '[tuck] Warning: On Windows, file permissions cannot be restricted to owner-only. ' +\n 'Ensure your secrets file is in a secure location not accessible to other users.'\n );\n windowsPermissionWarningShown = true;\n }\n }\n};\n\n// ============================================================================\n// Secret CRUD Operations\n// ============================================================================\n\n/**\n * Set (add or update) a secret\n */\nexport const setSecret = async (\n tuckDir: string,\n name: string,\n value: string,\n options?: {\n description?: string;\n source?: string;\n }\n): Promise<void> => {\n const store = await loadSecretsStore(tuckDir);\n const now = new Date().toISOString();\n\n store.secrets[name] = {\n value,\n placeholder: `{{${name}}}`,\n description: options?.description,\n source: options?.source,\n addedAt: store.secrets[name]?.addedAt || now,\n lastUsed: now,\n };\n\n await saveSecretsStore(tuckDir, store);\n};\n\n/**\n * Get a secret value by name\n */\nexport const getSecret = async (tuckDir: string, name: string): Promise<string | undefined> => {\n const store = await loadSecretsStore(tuckDir);\n return store.secrets[name]?.value;\n};\n\n/**\n * Remove a secret by name\n */\nexport const unsetSecret = async (tuckDir: string, name: string): Promise<boolean> => {\n const store = await loadSecretsStore(tuckDir);\n\n if (name in store.secrets) {\n delete store.secrets[name];\n await saveSecretsStore(tuckDir, store);\n return true;\n }\n\n return false;\n};\n\n/**\n * Check if a secret exists\n */\nexport const hasSecret = async (tuckDir: string, name: string): Promise<boolean> => {\n const store = await loadSecretsStore(tuckDir);\n return name in store.secrets;\n};\n\n// ============================================================================\n// Listing and Querying\n// ============================================================================\n\n/**\n * List all secrets (without values, for display)\n */\nexport const listSecrets = async (\n tuckDir: string\n): Promise<\n Array<{\n name: string;\n placeholder: string;\n description?: string;\n source?: string;\n addedAt: string;\n lastUsed?: string;\n }>\n> => {\n const store = await loadSecretsStore(tuckDir);\n\n return Object.entries(store.secrets).map(([name, entry]) => ({\n name,\n placeholder: entry.placeholder,\n description: entry.description,\n source: entry.source,\n addedAt: entry.addedAt,\n lastUsed: entry.lastUsed,\n }));\n};\n\n/**\n * Get all secrets as a name->value map (for restoration)\n */\nexport const getAllSecrets = async (tuckDir: string): Promise<Record<string, string>> => {\n const store = await loadSecretsStore(tuckDir);\n\n const result: Record<string, string> = {};\n for (const [name, entry] of Object.entries(store.secrets)) {\n result[name] = entry.value;\n }\n\n return result;\n};\n\n/**\n * Get secret count\n */\nexport const getSecretCount = async (tuckDir: string): Promise<number> => {\n const store = await loadSecretsStore(tuckDir);\n return Object.keys(store.secrets).length;\n};\n\n// ============================================================================\n// Bulk Operations\n// ============================================================================\n\n/**\n * Add multiple secrets at once\n */\nexport const setSecrets = async (\n tuckDir: string,\n secrets: Array<{\n name: string;\n value: string;\n description?: string;\n source?: string;\n }>\n): Promise<void> => {\n const store = await loadSecretsStore(tuckDir);\n const now = new Date().toISOString();\n\n for (const secret of secrets) {\n store.secrets[secret.name] = {\n value: secret.value,\n placeholder: `{{${secret.name}}}`,\n description: secret.description,\n source: secret.source,\n addedAt: store.secrets[secret.name]?.addedAt || now,\n lastUsed: now,\n };\n }\n\n await saveSecretsStore(tuckDir, store);\n};\n\n/**\n * Update lastUsed timestamp for secrets that were used\n */\nexport const touchSecrets = async (tuckDir: string, names: string[]): Promise<void> => {\n const store = await loadSecretsStore(tuckDir);\n const now = new Date().toISOString();\n\n let changed = false;\n for (const name of names) {\n if (name in store.secrets) {\n store.secrets[name].lastUsed = now;\n changed = true;\n }\n }\n\n if (changed) {\n await saveSecretsStore(tuckDir, store);\n }\n};\n\n// ============================================================================\n// Git Integration\n// ============================================================================\n\n/**\n * Ensure the secrets file is in .gitignore\n */\nexport const ensureSecretsGitignored = async (tuckDir: string): Promise<void> => {\n const gitignorePath = join(tuckDir, '.gitignore');\n\n let gitignoreContent = '';\n if (await pathExists(gitignorePath)) {\n gitignoreContent = await readFile(gitignorePath, 'utf-8');\n }\n\n // Check if already ignored\n if (gitignoreContent.includes(SECRETS_FILENAME)) {\n return;\n }\n\n // Add to .gitignore\n const newContent = gitignoreContent.trim()\n ? `${gitignoreContent.trim()}\\n\\n# Local secrets (NEVER commit)\\n${SECRETS_FILENAME}\\n`\n : `# Local secrets (NEVER commit)\\n${SECRETS_FILENAME}\\n`;\n\n await writeFile(gitignorePath, newContent, 'utf-8');\n};\n\n// ============================================================================\n// Validation\n// ============================================================================\n\n// Security: Maximum secret name length to prevent file system issues and abuse\nconst MAX_SECRET_NAME_LENGTH = 100;\nconst MIN_SECRET_NAME_LENGTH = 1;\n\n/**\n * Validate secret name format and length\n */\nexport const isValidSecretName = (name: string): boolean => {\n // Check length bounds\n if (name.length < MIN_SECRET_NAME_LENGTH || name.length > MAX_SECRET_NAME_LENGTH) {\n return false;\n }\n // Must be uppercase alphanumeric with underscores, starting with an uppercase letter (A-Z)\n return /^[A-Z][A-Z0-9_]*$/.test(name);\n};\n\n/**\n * Normalize a secret name to valid format\n * Security: Enforces length limits and validates result is not empty\n */\nexport const normalizeSecretName = (name: string): string => {\n let normalized = name\n .toUpperCase()\n .replace(/[^A-Z0-9_]/g, '_')\n .replace(/^[0-9_]+/, '') // Remove leading numbers and underscores\n .replace(/_+/g, '_') // Collapse multiple underscores\n .replace(/^_|_$/g, ''); // Trim leading/trailing underscores\n\n // Security: If normalization resulted in empty string, use a fallback\n if (normalized.length === 0) {\n normalized = 'SECRET';\n }\n\n // Security: Truncate to max length\n if (normalized.length > MAX_SECRET_NAME_LENGTH) {\n normalized = normalized.slice(0, MAX_SECRET_NAME_LENGTH);\n }\n\n // Ensure it starts with a letter (add prefix if needed)\n if (!/^[A-Z]/.test(normalized)) {\n normalized = 'S_' + normalized;\n if (normalized.length > MAX_SECRET_NAME_LENGTH) {\n normalized = normalized.slice(0, MAX_SECRET_NAME_LENGTH);\n }\n }\n\n return normalized;\n};\n","/**\n * Secret redaction and restoration for tuck\n *\n * Handles replacing secrets with placeholders in file content,\n * and restoring them from the local secrets store.\n */\n\nimport { readFile, writeFile, rename, unlink, stat } from 'fs/promises';\nimport { randomBytes } from 'crypto';\nimport { dirname, basename, join } from 'path';\nimport { expandPath, pathExists } from '../paths.js';\nimport type { SecretMatch } from './scanner.js';\nimport { getAllSecrets } from './store.js';\n\n// ============================================================================\n// Atomic File Operations\n// ============================================================================\n\n/**\n * Atomically write to a file by writing to a temp file first, then renaming.\n * This prevents data loss from race conditions or crashes during write.\n */\nconst atomicWriteFile = async (filepath: string, content: string): Promise<void> => {\n // Generate unique temp filename in same directory (for same-filesystem rename)\n const tempSuffix = randomBytes(8).toString('hex');\n const tempPath = join(dirname(filepath), `.${basename(filepath)}.tmp.${tempSuffix}`);\n\n try {\n // Get original file permissions if file exists\n let mode: number | undefined;\n let fileExists = false;\n try {\n const stats = await stat(filepath);\n mode = stats.mode;\n fileExists = true;\n } catch {\n // File doesn't exist\n }\n\n // Security: For new security-sensitive files (e.g., dotfiles), use restrictive permissions\n if (!fileExists && basename(filepath).startsWith('.')) {\n mode = 0o600; // Owner read/write only\n }\n\n // Write to temp file first\n await writeFile(tempPath, content, { encoding: 'utf-8', mode });\n\n // Atomically rename temp to target (this is atomic on POSIX systems)\n await rename(tempPath, filepath);\n } catch (error) {\n // Clean up temp file on error\n try {\n await unlink(tempPath);\n } catch {\n // Ignore cleanup errors\n }\n throw error;\n }\n};\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RedactionResult {\n originalContent: string;\n redactedContent: string;\n replacements: Array<{\n placeholder: string;\n originalValue: string;\n line: number;\n }>;\n}\n\nexport interface RestorationResult {\n originalContent: string;\n restoredContent: string;\n restored: number;\n unresolved: string[];\n}\n\n// ============================================================================\n// Placeholder Formatting\n// ============================================================================\n\n/**\n * Format a placeholder name into placeholder syntax\n */\nexport const formatPlaceholder = (name: string): string => {\n return `{{${name}}}`;\n};\n\n/**\n * Extract placeholder name from placeholder syntax\n */\nexport const parsePlaceholder = (placeholder: string): string | null => {\n const match = placeholder.match(/^\\{\\{([A-Z][A-Z0-9_]*)\\}\\}$/);\n return match ? match[1] : null;\n};\n\n/**\n * Regex to find all placeholders in content\n */\nexport const PLACEHOLDER_REGEX = /\\{\\{([A-Z][A-Z0-9_]*)\\}\\}/g;\n\n// ============================================================================\n// Content Redaction\n// ============================================================================\n\n/**\n * Redact secrets in content string with placeholders\n */\nexport const redactContent = (\n content: string,\n matches: SecretMatch[],\n placeholderMap: Map<string, string> // secret value -> placeholder name\n): RedactionResult => {\n let redactedContent = content;\n const replacements: RedactionResult['replacements'] = [];\n\n // Process all matches and replace secret values with placeholders\n // Note: The split/join approach processes content multiple times, which could be\n // optimized for large files by processing matches in reverse order by position.\n // However, this approach is simpler and works well for typical config files.\n for (const match of matches) {\n const placeholderName = placeholderMap.get(match.value) || match.placeholder;\n const placeholder = formatPlaceholder(placeholderName);\n\n // Replace all occurrences of this secret value\n // Use a temporary marker to avoid replacing already-replaced content\n // Security: Use crypto.randomBytes for unpredictable temp markers\n const tempMarker = `__TUCK_TEMP_${randomBytes(16).toString('hex')}__`;\n redactedContent = redactedContent.split(match.value).join(tempMarker);\n redactedContent = redactedContent.split(tempMarker).join(placeholder);\n\n replacements.push({\n placeholder: placeholderName,\n originalValue: match.value,\n line: match.line,\n });\n }\n\n return {\n originalContent: content,\n redactedContent,\n replacements: replacements.reverse(), // Return in reverse line order (last line first) so callers can safely apply replacements without affecting subsequent line positions\n };\n};\n\n/**\n * Redact a file in place, returning the mapping for storage\n */\nexport const redactFile = async (\n filepath: string,\n matches: SecretMatch[],\n placeholderMap: Map<string, string>\n): Promise<RedactionResult> => {\n const expandedPath = expandPath(filepath);\n const content = await readFile(expandedPath, 'utf-8');\n\n const result = redactContent(content, matches, placeholderMap);\n\n // Security: Use atomic write to prevent data loss from race conditions\n await atomicWriteFile(expandedPath, result.redactedContent);\n\n return result;\n};\n\n// ============================================================================\n// Content Restoration\n// ============================================================================\n\n/**\n * Restore secrets in content string from placeholders\n */\nexport const restoreContent = (\n content: string,\n secrets: Record<string, string> // placeholder name -> actual value\n): RestorationResult => {\n let restoredContent = content;\n let restored = 0;\n const unresolved: string[] = [];\n const seenUnresolved = new Set<string>();\n\n // Find all placeholders in the content\n const matches = [...content.matchAll(PLACEHOLDER_REGEX)];\n\n for (const match of matches) {\n const placeholderName = match[1];\n const fullPlaceholder = match[0];\n\n if (placeholderName in secrets) {\n // Replace this placeholder with actual value\n restoredContent = restoredContent.replaceAll(fullPlaceholder, secrets[placeholderName]);\n restored++;\n } else if (!seenUnresolved.has(placeholderName)) {\n // Track unresolved placeholders\n unresolved.push(placeholderName);\n seenUnresolved.add(placeholderName);\n }\n }\n\n return {\n originalContent: content,\n restoredContent,\n restored,\n unresolved,\n };\n};\n\n/**\n * Restore a file in place from the secrets store\n */\nexport const restoreFile = async (\n filepath: string,\n tuckDir: string\n): Promise<{ restored: number; unresolved: string[] }> => {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n return { restored: 0, unresolved: [] };\n }\n\n const content = await readFile(expandedPath, 'utf-8');\n const secrets = await getAllSecrets(tuckDir);\n\n const result = restoreContent(content, secrets);\n\n // Only write if changes were made\n if (result.restored > 0) {\n // Security: Use atomic write to prevent data loss from race conditions\n await atomicWriteFile(expandedPath, result.restoredContent);\n }\n\n return {\n restored: result.restored,\n unresolved: result.unresolved,\n };\n};\n\n// ============================================================================\n// Placeholder Detection\n// ============================================================================\n\n/**\n * Find all placeholders in content\n */\nexport const findPlaceholders = (content: string): string[] => {\n const placeholders: string[] = [];\n const matches = content.matchAll(PLACEHOLDER_REGEX);\n\n for (const match of matches) {\n if (!placeholders.includes(match[1])) {\n placeholders.push(match[1]);\n }\n }\n\n return placeholders;\n};\n\n/**\n * Find unresolved placeholders in content (those without stored values)\n */\nexport const findUnresolvedPlaceholders = (\n content: string,\n availableSecrets: Record<string, string>\n): string[] => {\n const placeholders = findPlaceholders(content);\n return placeholders.filter((name) => !(name in availableSecrets));\n};\n\n/**\n * Check if content has any placeholders\n */\nexport const hasPlaceholders = (content: string): boolean => {\n // Use a cloned regex instance to avoid shared lastIndex state issues\n const regex = new RegExp(PLACEHOLDER_REGEX.source, PLACEHOLDER_REGEX.flags);\n return regex.test(content);\n};\n\n/**\n * Count placeholders in content\n */\nexport const countPlaceholders = (content: string): number => {\n const matches = content.match(PLACEHOLDER_REGEX);\n return matches ? matches.length : 0;\n};\n\n// ============================================================================\n// Batch Operations\n// ============================================================================\n\n/**\n * Restore multiple files in place\n */\nexport const restoreFiles = async (\n filepaths: string[],\n tuckDir: string\n): Promise<{\n totalRestored: number;\n filesModified: number;\n allUnresolved: string[];\n}> => {\n const secrets = await getAllSecrets(tuckDir);\n let totalRestored = 0;\n let filesModified = 0;\n const allUnresolved = new Set<string>();\n\n for (const filepath of filepaths) {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n continue;\n }\n\n const content = await readFile(expandedPath, 'utf-8');\n const result = restoreContent(content, secrets);\n\n if (result.restored > 0) {\n // Security: Use atomic write to prevent data loss from race conditions\n await atomicWriteFile(expandedPath, result.restoredContent);\n totalRestored += result.restored;\n filesModified++;\n }\n\n for (const unresolved of result.unresolved) {\n allUnresolved.add(unresolved);\n }\n }\n\n return {\n totalRestored,\n filesModified,\n allUnresolved: [...allUnresolved],\n };\n};\n\n/**\n * Preview what placeholders would be restored without modifying files\n */\nexport const previewRestoration = async (\n filepath: string,\n tuckDir: string\n): Promise<{\n wouldRestore: number;\n unresolved: string[];\n placeholders: string[];\n}> => {\n const expandedPath = expandPath(filepath);\n\n if (!(await pathExists(expandedPath))) {\n return { wouldRestore: 0, unresolved: [], placeholders: [] };\n }\n\n const content = await readFile(expandedPath, 'utf-8');\n const secrets = await getAllSecrets(tuckDir);\n const placeholders = findPlaceholders(content);\n\n const resolved = placeholders.filter((p) => p in secrets);\n const unresolved = placeholders.filter((p) => !(p in secrets));\n\n return {\n wouldRestore: resolved.length,\n unresolved,\n placeholders,\n };\n};\n","/**\n * External secret scanner integration\n *\n * Provides optional integration with external tools like gitleaks and trufflehog.\n * Falls back to built-in scanning if external tools are not available.\n */\n\n// Security: Use execFile instead of exec to prevent command injection\n// execFile doesn't use shell interpolation, so malicious filenames can't execute arbitrary commands\nimport { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport { z } from 'zod';\nimport type { SecretMatch, FileScanResult, ScanSummary } from './scanner.js';\nimport { scanFiles as builtinScanFiles, redactSecret } from './scanner.js';\nimport type { SecretSeverity } from './patterns.js';\nimport { collapsePath } from '../paths.js';\n\nconst execFileAsync = promisify(execFile);\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ExternalScanner = 'gitleaks' | 'trufflehog' | 'builtin';\n\n// Security: Zod schema for validating gitleaks JSON output\n// This prevents prototype pollution and ensures type safety from external tool output\nconst gitleaksResultSchema = z.object({\n Description: z.string(),\n StartLine: z.number(),\n EndLine: z.number(),\n StartColumn: z.number(),\n EndColumn: z.number(),\n Match: z.string(),\n Secret: z.string(),\n File: z.string(),\n SymlinkFile: z.string().optional().default(''),\n Commit: z.string().optional().default(''),\n Entropy: z.number().optional().default(0),\n Author: z.string().optional().default(''),\n Email: z.string().optional().default(''),\n Date: z.string().optional().default(''),\n Message: z.string().optional().default(''),\n Tags: z.array(z.string()).optional().default([]),\n RuleID: z.string(),\n Fingerprint: z.string().optional().default(''),\n});\n\nconst gitleaksOutputSchema = z.array(gitleaksResultSchema);\n\ntype GitleaksResult = z.infer<typeof gitleaksResultSchema>;\n\n// ============================================================================\n// Scanner Detection\n// ============================================================================\n\n/**\n * Check if gitleaks is installed\n */\nexport const isGitleaksInstalled = async (): Promise<boolean> => {\n try {\n // Security: Use execFileAsync to prevent command injection\n await execFileAsync('gitleaks', ['version']);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Check if trufflehog is installed\n */\nexport const isTrufflehogInstalled = async (): Promise<boolean> => {\n try {\n // Security: Use execFileAsync to prevent command injection\n await execFileAsync('trufflehog', ['--version']);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Get available scanners\n */\nexport const getAvailableScanners = async (): Promise<ExternalScanner[]> => {\n const available: ExternalScanner[] = ['builtin'];\n\n if (await isGitleaksInstalled()) {\n available.push('gitleaks');\n }\n\n if (await isTrufflehogInstalled()) {\n available.push('trufflehog');\n }\n\n return available;\n};\n\n// ============================================================================\n// Gitleaks Integration\n// ============================================================================\n\n/**\n * Map gitleaks severity/rule to our severity levels\n */\nconst mapGitleaksSeverity = (ruleId: string): SecretSeverity => {\n // Critical patterns\n const criticalPatterns = [\n 'aws', 'gcp', 'azure', 'private-key', 'stripe', 'github',\n 'gitlab', 'npm', 'pypi', 'jwt', 'oauth',\n ];\n\n // High severity patterns\n const highPatterns = [\n 'api', 'token', 'secret', 'password', 'credential',\n ];\n\n const ruleIdLower = ruleId.toLowerCase();\n\n if (criticalPatterns.some(p => ruleIdLower.includes(p))) {\n return 'critical';\n }\n\n if (highPatterns.some(p => ruleIdLower.includes(p))) {\n return 'high';\n }\n\n return 'medium';\n};\n\n/**\n * Generate a placeholder name from gitleaks rule\n */\nconst generatePlaceholderFromRule = (ruleId: string): string => {\n return ruleId\n .toUpperCase()\n .replace(/-/g, '_')\n .replace(/[^A-Z0-9_]/g, '');\n};\n\n/**\n * Scan files using gitleaks\n */\nexport const scanWithGitleaks = async (filepaths: string[]): Promise<ScanSummary> => {\n const results: FileScanResult[] = [];\n let totalSecrets = 0;\n let filesWithSecrets = 0;\n const bySeverity = { critical: 0, high: 0, medium: 0, low: 0 };\n\n // Run gitleaks on files in parallel batches (with concurrency limit)\n const CONCURRENCY = 5; // Lower concurrency for external process spawning\n\n for (let i = 0; i < filepaths.length; i += CONCURRENCY) {\n const batch = filepaths.slice(i, i + CONCURRENCY);\n const batchResults = await Promise.all(\n batch.map(async (filepath): Promise<FileScanResult | null> => {\n try {\n // Security: Use execFileAsync with array arguments to prevent command injection\n // This prevents malicious filenames from executing arbitrary shell commands\n const { stdout, stderr } = await execFileAsync('gitleaks', [\n 'detect',\n '--source', filepath,\n '--no-git',\n '--report-format', 'json',\n '--exit-code', '0'\n ], { maxBuffer: 10 * 1024 * 1024 });\n\n // Check stderr for gitleaks errors (not just secret findings)\n if (stderr && stderr.trim()) {\n // Log stderr but continue - gitleaks may output warnings/errors to stderr\n console.warn(`[tuck] Gitleaks stderr for ${filepath}: ${stderr.trim()}`);\n }\n\n if (!stdout.trim()) return null;\n\n // Security: Use Zod to validate external JSON input\n // This prevents prototype pollution and ensures type safety\n let gitleaksResults: GitleaksResult[];\n try {\n const rawData = JSON.parse(stdout);\n const validated = gitleaksOutputSchema.safeParse(rawData);\n\n if (!validated.success) {\n console.warn(`[tuck] Warning: Invalid gitleaks output format for ${filepath}: ${validated.error.message}`);\n return null;\n }\n\n gitleaksResults = validated.data;\n } catch (parseError) {\n // Log parse error for debugging instead of silent failure\n console.warn(`[tuck] Warning: Failed to parse gitleaks JSON for ${filepath}`);\n return null;\n }\n\n if (gitleaksResults.length === 0) return null;\n\n const matches: SecretMatch[] = [];\n\n for (const finding of gitleaksResults) {\n const severity = mapGitleaksSeverity(finding.RuleID);\n\n // Security: Use consistent redactSecret function for better security\n const secretValue = finding.Secret || finding.Match;\n const redactedValue = redactSecret(secretValue);\n\n matches.push({\n patternId: `gitleaks-${finding.RuleID}`,\n patternName: finding.Description || finding.RuleID,\n severity,\n line: finding.StartLine,\n column: finding.StartColumn,\n value: secretValue,\n redactedValue,\n context: finding.Match,\n placeholder: generatePlaceholderFromRule(finding.RuleID),\n });\n }\n\n // Collapse home directory in path for display using utility function\n const collapsedPath = collapsePath(filepath);\n\n return {\n path: filepath,\n collapsedPath,\n hasSecrets: true,\n matches,\n criticalCount: matches.filter(m => m.severity === 'critical').length,\n highCount: matches.filter(m => m.severity === 'high').length,\n mediumCount: matches.filter(m => m.severity === 'medium').length,\n lowCount: matches.filter(m => m.severity === 'low').length,\n skipped: false,\n };\n } catch (execError) {\n // Log error for debugging instead of silent failure\n const errorMsg = execError instanceof Error ? execError.message : String(execError);\n console.warn(`[tuck] Warning: Gitleaks scan failed for ${filepath}: ${errorMsg}`);\n return null;\n }\n })\n );\n\n // Process batch results\n for (const result of batchResults) {\n if (result) {\n results.push(result);\n filesWithSecrets++;\n totalSecrets += result.matches.length;\n for (const match of result.matches) {\n bySeverity[match.severity]++;\n }\n }\n }\n }\n\n return {\n results,\n totalFiles: filepaths.length,\n scannedFiles: filepaths.length,\n skippedFiles: 0,\n filesWithSecrets,\n totalSecrets,\n bySeverity,\n };\n};\n\n// ============================================================================\n// Scanner Factory\n// ============================================================================\n\n/**\n * Scan files using the specified scanner (or fallback to builtin)\n */\nexport const scanWithScanner = async (\n filepaths: string[],\n scanner: ExternalScanner = 'builtin'\n): Promise<ScanSummary> => {\n if (scanner === 'gitleaks') {\n const isInstalled = await isGitleaksInstalled();\n if (isInstalled) {\n return scanWithGitleaks(filepaths);\n }\n // Fall back to builtin if gitleaks not available\n console.warn('gitleaks not found, falling back to built-in scanner');\n }\n\n if (scanner === 'trufflehog') {\n // Trufflehog integration could be added here\n // For now, fall back to builtin\n console.warn('trufflehog integration not yet implemented, using built-in scanner');\n }\n\n // Use built-in scanner\n return builtinScanFiles(filepaths);\n};\n","/**\n * Secret scanning and management for tuck\n *\n * This module provides comprehensive secret detection, redaction,\n * and management capabilities for dotfiles.\n */\n\n// Re-export pattern types and helpers\nexport {\n type SecretPattern,\n type SecretSeverity,\n ALL_SECRET_PATTERNS,\n CLOUD_PROVIDER_PATTERNS,\n API_TOKEN_PATTERNS,\n PRIVATE_KEY_PATTERNS,\n GENERIC_PATTERNS,\n getPatternById,\n getPatternsBySeverity,\n getPatternsAboveSeverity,\n createCustomPattern,\n shouldSkipFile,\n BINARY_EXTENSIONS,\n} from './patterns.js';\n\n// Re-export scanner types and functions\nexport {\n type SecretMatch,\n type FileScanResult,\n type ScanOptions,\n type ScanSummary,\n scanContent,\n scanFile,\n scanFiles,\n generateUniquePlaceholder,\n getSecretsWithPlaceholders,\n} from './scanner.js';\n\n// Re-export store types and functions\nexport {\n getSecretsPath,\n loadSecretsStore,\n saveSecretsStore,\n setSecret,\n getSecret,\n unsetSecret,\n hasSecret,\n listSecrets,\n getAllSecrets,\n getSecretCount,\n setSecrets,\n touchSecrets,\n ensureSecretsGitignored,\n isValidSecretName,\n normalizeSecretName,\n} from './store.js';\n\n// Re-export redactor types and functions\nexport {\n type RedactionResult,\n type RestorationResult,\n formatPlaceholder,\n parsePlaceholder,\n PLACEHOLDER_REGEX,\n redactContent,\n redactFile,\n restoreContent,\n restoreFile,\n findPlaceholders,\n findUnresolvedPlaceholders,\n hasPlaceholders,\n countPlaceholders,\n restoreFiles,\n previewRestoration,\n} from './redactor.js';\n\n// Re-export schema types\nexport type { SecurityConfig, CustomPattern, SecretEntry, SecretsStore } from '../../schemas/secrets.schema.js';\n\n// Re-export external scanner types and functions\nexport {\n type ExternalScanner,\n isGitleaksInstalled,\n isTrufflehogInstalled,\n getAvailableScanners,\n scanWithGitleaks,\n scanWithScanner,\n} from './external.js';\n\n// ============================================================================\n// High-Level Convenience Functions\n// ============================================================================\n\nimport { loadConfig } from '../config.js';\nimport { scanFiles, type ScanSummary, type FileScanResult } from './scanner.js';\nimport { setSecret, ensureSecretsGitignored } from './store.js';\nimport { createCustomPattern, type SecretPattern } from './patterns.js';\nimport type { CustomPattern } from '../../schemas/secrets.schema.js';\nimport { scanWithScanner, isGitleaksInstalled, isTrufflehogInstalled, type ExternalScanner } from './external.js';\n\n/**\n * Scan files for secrets using config-aware settings\n *\n * Supports external scanners (gitleaks, trufflehog) via config.\n * Falls back to built-in scanner if external tool not available.\n */\nexport const scanForSecrets = async (filepaths: string[], tuckDir: string): Promise<ScanSummary> => {\n const config = await loadConfig(tuckDir);\n const security = config.security || {};\n\n // Check if an external scanner is configured\n const configuredScanner = (security.scanner || 'builtin') as ExternalScanner;\n\n // If external scanner configured, try to use it\n if (configuredScanner !== 'builtin') {\n // Check availability\n let useExternal = false;\n if (configuredScanner === 'gitleaks' && await isGitleaksInstalled()) {\n useExternal = true;\n } else if (configuredScanner === 'trufflehog' && await isTrufflehogInstalled()) {\n useExternal = true;\n }\n\n if (useExternal) {\n return scanWithScanner(filepaths, configuredScanner);\n }\n // Fall through to built-in if external not available\n }\n\n // Use built-in scanner with custom patterns\n const customPatterns: SecretPattern[] = (security.customPatterns || []).map((p: CustomPattern, i: number) =>\n createCustomPattern(`config-${i}`, p.name || `Custom Pattern ${i + 1}`, p.pattern, {\n severity: p.severity,\n description: p.description,\n placeholder: p.placeholder,\n flags: p.flags,\n })\n );\n\n return scanFiles(filepaths, {\n customPatterns: customPatterns.length > 0 ? customPatterns : undefined,\n excludePatternIds: security.excludePatterns,\n minSeverity: security.minSeverity,\n maxFileSize: security.maxFileSize,\n });\n};\n\n/**\n * Process scan results: store secrets and return placeholder mapping\n */\nexport const processSecretsForRedaction = async (\n results: FileScanResult[],\n tuckDir: string\n): Promise<Map<string, Map<string, string>>> => {\n await ensureSecretsGitignored(tuckDir);\n\n // Map of filepath -> (secret value -> placeholder name)\n const fileRedactionMaps = new Map<string, Map<string, string>>();\n\n // Track used placeholders to ensure uniqueness\n const usedPlaceholders = new Set<string>();\n\n for (const result of results) {\n const placeholderMap = new Map<string, string>();\n\n for (const match of result.matches) {\n // Check if we already have this value mapped\n let existingPlaceholder: string | undefined;\n \n // First check the current file's map to avoid duplicates within the same file\n if (placeholderMap.has(match.value)) {\n existingPlaceholder = placeholderMap.get(match.value);\n } else {\n // Then check previous files\n for (const map of fileRedactionMaps.values()) {\n if (map.has(match.value)) {\n existingPlaceholder = map.get(match.value);\n break;\n }\n }\n }\n\n let placeholder: string;\n if (existingPlaceholder) {\n // Reuse existing placeholder for same value\n placeholder = existingPlaceholder;\n } else {\n // Generate unique placeholder\n placeholder = match.placeholder;\n let counter = 1;\n while (usedPlaceholders.has(placeholder)) {\n placeholder = `${match.placeholder}_${counter}`;\n counter++;\n }\n usedPlaceholders.add(placeholder);\n\n // Store the secret\n await setSecret(tuckDir, placeholder, match.value, {\n description: match.patternName,\n source: result.collapsedPath,\n });\n }\n\n placeholderMap.set(match.value, placeholder);\n }\n\n fileRedactionMaps.set(result.path, placeholderMap);\n }\n\n return fileRedactionMaps;\n};\n\n/**\n * Check if secret scanning is enabled in config\n */\nexport const isSecretScanningEnabled = async (tuckDir: string): Promise<boolean> => {\n try {\n const config = await loadConfig(tuckDir);\n return config.security?.scanSecrets !== false;\n } catch (error) {\n // Log error for debugging instead of silent failure\n const errorMsg = error instanceof Error ? error.message : String(error);\n console.warn(`[tuck] Warning: Failed to load config for scanning check: ${errorMsg}`);\n // Default to enabled if config can't be loaded (safe default)\n return true;\n }\n};\n\n/**\n * Check if operations should be blocked when secrets are detected\n */\nexport const shouldBlockOnSecrets = async (tuckDir: string): Promise<boolean> => {\n try {\n const config = await loadConfig(tuckDir);\n return config.security?.blockOnSecrets !== false;\n } catch (error) {\n // Log error for debugging instead of silent failure\n const errorMsg = error instanceof Error ? error.message : String(error);\n console.warn(`[tuck] Warning: Failed to load config for blocking check: ${errorMsg}`);\n // Default to blocking if config can't be loaded (safe default)\n return true;\n }\n};\n","/**\n * tuck secrets - Manage local secrets for placeholder replacement\n *\n * Commands:\n * tuck secrets list - List all stored secrets (values hidden)\n * tuck secrets set <n> <v> - Set a secret value\n * tuck secrets unset <name> - Remove a secret\n * tuck secrets path - Show path to secrets file\n * tuck secrets scan-history - Scan git history for leaked secrets\n */\n\nimport { Command } from 'commander';\nimport { prompts, logger, colors as c } from '../ui/index.js';\nimport { getTuckDir, expandPath, pathExists } from '../lib/paths.js';\nimport { loadManifest } from '../lib/manifest.js';\nimport {\n listSecrets,\n setSecret,\n unsetSecret,\n getSecretsPath,\n isValidSecretName,\n normalizeSecretName,\n scanForSecrets,\n type ScanSummary,\n} from '../lib/secrets/index.js';\nimport { NotInitializedError } from '../errors.js';\nimport { getLog } from '../lib/git.js';\n\n// ============================================================================\n// List Command\n// ============================================================================\n\nconst runSecretsList = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n const secrets = await listSecrets(tuckDir);\n\n if (secrets.length === 0) {\n logger.info('No secrets stored');\n logger.dim(`Secrets file: ${getSecretsPath(tuckDir)}`);\n console.log();\n logger.dim('Secrets are stored when you choose to replace detected secrets with placeholders.');\n logger.dim('You can also manually add secrets with: tuck secrets set <NAME> <value>');\n return;\n }\n\n console.log();\n console.log(c.bold.cyan(`Stored Secrets (${secrets.length})`));\n console.log(c.dim('─'.repeat(50)));\n console.log();\n\n for (const secret of secrets) {\n console.log(` ${c.green(secret.name)}`);\n console.log(` ${c.dim('Placeholder:')} ${c.cyan(secret.placeholder)}`);\n if (secret.description) {\n console.log(` ${c.dim('Type:')} ${secret.description}`);\n }\n if (secret.source) {\n console.log(` ${c.dim('Source:')} ${secret.source}`);\n }\n console.log(` ${c.dim('Added:')} ${new Date(secret.addedAt).toLocaleDateString()}`);\n console.log();\n }\n\n logger.dim(`Secrets file: ${getSecretsPath(tuckDir)}`);\n};\n\n// ============================================================================\n// Set Command\n// ============================================================================\n\nconst runSecretsSet = async (name: string): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Validate or normalize name\n if (!isValidSecretName(name)) {\n const normalized = normalizeSecretName(name);\n logger.warning(`Secret name normalized to: ${normalized}`);\n logger.dim('Secret names must be uppercase alphanumeric with underscores (e.g., API_KEY)');\n name = normalized;\n }\n\n // Security: Always prompt for secret value interactively\n // Never accept via command-line to prevent exposure in shell history and process list\n // Note: Cancellation or empty input is handled below by validating the returned value.\n const secretValue = await prompts.password(`Enter value for ${name}:`);\n\n if (!secretValue || secretValue.trim().length === 0) {\n logger.error('Secret value cannot be empty');\n return;\n }\n\n await setSecret(tuckDir, name, secretValue);\n logger.success(`Secret '${name}' set`);\n console.log();\n logger.dim(`Use {{${name}}} as placeholder in your dotfiles`);\n};\n\n// ============================================================================\n// Unset Command\n// ============================================================================\n\nconst runSecretsUnset = async (name: string): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n const removed = await unsetSecret(tuckDir, name);\n\n if (removed) {\n logger.success(`Secret '${name}' removed`);\n } else {\n logger.warning(`Secret '${name}' not found`);\n logger.dim('Run `tuck secrets list` to see stored secrets');\n }\n};\n\n// ============================================================================\n// Path Command\n// ============================================================================\n\nconst runSecretsPath = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n console.log(getSecretsPath(tuckDir));\n};\n\n// ============================================================================\n// Scan History Command\n// ============================================================================\n\ninterface HistoryScanResult {\n commit: string;\n author: string;\n date: string;\n message: string;\n secrets: Array<{\n file: string;\n pattern: string;\n severity: string;\n redactedValue: string;\n }>;\n}\n\nconst runScanHistory = async (options: { since?: string; limit?: string }): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n const limit = options.limit ? parseInt(options.limit, 10) : 50;\n\n prompts.intro('tuck secrets scan-history');\n\n const spinner = prompts.spinner();\n spinner.start('Scanning git history for secrets...');\n\n try {\n // Get commit log using existing function\n const logEntries = await getLog(tuckDir, {\n maxCount: limit,\n since: options.since,\n });\n\n if (logEntries.length === 0) {\n spinner.stop('No commits found');\n return;\n }\n\n // Import simpleGit directly for diff operations\n let simpleGit;\n try {\n simpleGit = (await import('simple-git')).default;\n } catch (importError) {\n spinner.stop('Git integration is unavailable (simple-git module could not be loaded).');\n const errorMsg = importError instanceof Error ? importError.message : String(importError);\n logger.error(`Failed to load simple-git for scan-history: ${errorMsg}`);\n return;\n }\n const git = simpleGit(tuckDir);\n\n const results: HistoryScanResult[] = [];\n let scannedCommits = 0;\n\n for (const entry of logEntries) {\n scannedCommits++;\n spinner.message(`Scanning commit ${scannedCommits}/${logEntries.length}...`);\n\n // Get diff for this commit\n try {\n const diff = await git.diff([`${entry.hash}^`, entry.hash]);\n\n if (diff) {\n // Extract added lines (those starting with +)\n const addedLines = diff\n .split('\\n')\n .filter((line: string) => line.startsWith('+') && !line.startsWith('+++'))\n .map((line: string) => line.slice(1))\n .join('\\n');\n\n if (addedLines) {\n // Scan the added content\n const { scanContent } = await import('../lib/secrets/scanner.js');\n const matches = scanContent(addedLines);\n\n if (matches.length > 0) {\n results.push({\n commit: entry.hash.slice(0, 8),\n author: entry.author,\n date: entry.date,\n message: entry.message.slice(0, 50),\n secrets: matches.map((m) => ({\n file: 'diff',\n pattern: m.patternName,\n severity: m.severity,\n redactedValue: m.redactedValue,\n })),\n });\n }\n }\n }\n } catch (error) {\n // Skip commits that can't be diffed (e.g., initial commit), but log for visibility\n const errorMsg = error instanceof Error ? error.message : String(error);\n logger.warning(\n `Skipping commit ${entry.hash.slice(\n 0,\n 8\n )}: unable to diff against parent (possibly initial/root commit). ${errorMsg}`\n );\n continue;\n }\n }\n\n spinner.stop(`Scanned ${scannedCommits} commits`);\n\n if (results.length === 0) {\n console.log();\n logger.success('No secrets found in git history');\n prompts.outro('Clean history!');\n return;\n }\n\n // Display results\n console.log();\n console.log(c.bold.red(`Found potential secrets in ${results.length} commits`));\n console.log(c.dim('─'.repeat(60)));\n console.log();\n\n for (const result of results) {\n console.log(c.yellow(`Commit: ${result.commit}`));\n console.log(c.dim(` Author: ${result.author}`));\n console.log(c.dim(` Date: ${result.date}`));\n console.log(c.dim(` Message: ${result.message}`));\n console.log();\n\n for (const secret of result.secrets) {\n const severityColor =\n secret.severity === 'critical' ? c.red : secret.severity === 'high' ? c.yellow : c.dim;\n console.log(` ${severityColor(`[${secret.severity}]`)} ${secret.pattern}`);\n console.log(c.dim(` Value: ${secret.redactedValue}`));\n }\n console.log();\n }\n\n console.log(c.dim('─'.repeat(60)));\n console.log();\n logger.warning('If these secrets are still valid, rotate them immediately!');\n console.log();\n logger.dim('To remove secrets from git history, consider using:');\n logger.dim(' - git filter-branch');\n logger.dim(' - BFG Repo-Cleaner (https://rtyley.github.io/bfg-repo-cleaner/)');\n\n prompts.outro(c.red(`${results.length} commits with potential secrets`));\n } catch (error) {\n spinner.stop('Scan failed');\n throw error;\n }\n};\n\n// ============================================================================\n// Interactive Scan Command\n// ============================================================================\n\nconst runScanFiles = async (paths: string[]): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n if (paths.length === 0) {\n logger.error('No files specified');\n logger.dim('Usage: tuck secrets scan <file> [files...]');\n return;\n }\n\n // Expand paths\n const expandedPaths = paths.map((p) => expandPath(p));\n\n // Check files exist\n for (const path of expandedPaths) {\n if (!(await pathExists(path))) {\n logger.warning(`File not found: ${path}`);\n }\n }\n\n const existingPaths = [];\n for (const path of expandedPaths) {\n if (await pathExists(path)) {\n existingPaths.push(path);\n }\n }\n\n if (existingPaths.length === 0) {\n logger.error('No valid files to scan');\n return;\n }\n\n const spinner = prompts.spinner();\n spinner.start(`Scanning ${existingPaths.length} file(s)...`);\n\n const summary = await scanForSecrets(existingPaths, tuckDir);\n\n spinner.stop('Scan complete');\n\n if (summary.filesWithSecrets === 0) {\n console.log();\n logger.success('No secrets detected');\n return;\n }\n\n // Display results\n displayScanResults(summary);\n};\n\n/**\n * Display scan results in a formatted way\n */\nexport const displayScanResults = (summary: ScanSummary): void => {\n console.log();\n console.log(\n c.bold.red(\n `Found ${summary.totalSecrets} potential secret(s) in ${summary.filesWithSecrets} file(s)`\n )\n );\n console.log(c.dim('─'.repeat(60)));\n console.log();\n\n // Summary by severity\n if (summary.bySeverity.critical > 0) {\n console.log(c.red(` Critical: ${summary.bySeverity.critical}`));\n }\n if (summary.bySeverity.high > 0) {\n console.log(c.yellow(` High: ${summary.bySeverity.high}`));\n }\n if (summary.bySeverity.medium > 0) {\n console.log(c.blue(` Medium: ${summary.bySeverity.medium}`));\n }\n if (summary.bySeverity.low > 0) {\n console.log(c.dim(` Low: ${summary.bySeverity.low}`));\n }\n console.log();\n\n // Details by file\n for (const result of summary.results) {\n console.log(c.cyan(result.collapsedPath));\n\n for (const match of result.matches) {\n const severityColor =\n match.severity === 'critical'\n ? c.red\n : match.severity === 'high'\n ? c.yellow\n : match.severity === 'medium'\n ? c.blue\n : c.dim;\n\n console.log(\n ` ${c.dim(`Line ${match.line}:`)} ${severityColor(`[${match.severity}]`)} ${match.patternName}`\n );\n console.log(c.dim(` ${match.context}`));\n }\n console.log();\n }\n};\n\n// ============================================================================\n// Command Definition\n// ============================================================================\n\nexport const secretsCommand = new Command('secrets')\n .description('Manage local secrets for placeholder replacement')\n .action(async () => {\n // Default action: show list\n await runSecretsList();\n })\n .addCommand(\n new Command('list')\n .description('List all stored secrets (values hidden)')\n .action(runSecretsList)\n )\n .addCommand(\n new Command('set')\n .description('Set a secret value (prompts securely)')\n .argument('<name>', 'Secret name (e.g., GITHUB_TOKEN)')\n .action(runSecretsSet)\n )\n .addCommand(\n new Command('unset')\n .description('Remove a secret')\n .argument('<name>', 'Secret name to remove')\n .action(runSecretsUnset)\n )\n .addCommand(new Command('path').description('Show path to secrets file').action(runSecretsPath))\n .addCommand(\n new Command('scan')\n .description('Scan files for secrets')\n .argument('[paths...]', 'Files to scan')\n .action(runScanFiles)\n )\n .addCommand(\n new Command('scan-history')\n .description('Scan git history for leaked secrets')\n .option('--since <date>', 'Only scan commits after this date (e.g., 2024-01-01)')\n .option('--limit <n>', 'Maximum number of commits to scan', '50')\n .action(runScanHistory)\n );\n","import { Command } from 'commander';\nimport { join } from 'path';\nimport { prompts, logger, withSpinner, colors as c } from '../ui/index.js';\nimport { getTuckDir, expandPath, pathExists, collapsePath } from '../lib/paths.js';\nimport {\n loadManifest,\n getAllTrackedFiles,\n updateFileInManifest,\n removeFileFromManifest,\n getTrackedFileBySource,\n} from '../lib/manifest.js';\nimport { stageAll, commit, getStatus, push, hasRemote, fetch, pull } from '../lib/git.js';\nimport {\n copyFileOrDir,\n getFileChecksum,\n deleteFileOrDir,\n checkFileSizeThreshold,\n formatFileSize,\n SIZE_BLOCK_THRESHOLD,\n} from '../lib/files.js';\nimport { addToTuckignore, loadTuckignore, isIgnored } from '../lib/tuckignore.js';\nimport { runPreSyncHook, runPostSyncHook, type HookOptions } from '../lib/hooks.js';\nimport { NotInitializedError, SecretsDetectedError } from '../errors.js';\nimport type { SyncOptions, FileChange } from '../types.js';\nimport { detectDotfiles, DETECTION_CATEGORIES, type DetectedFile } from '../lib/detect.js';\nimport { trackFilesWithProgress, type FileToTrack } from '../lib/fileTracking.js';\nimport { scanForSecrets, isSecretScanningEnabled } from '../lib/secrets/index.js';\nimport { displayScanResults } from './secrets.js';\n\ninterface SyncResult {\n modified: string[];\n deleted: string[];\n commitHash?: string;\n // Note: There is no 'added' array because adding new files is done via 'tuck add', not 'tuck sync'.\n // The sync command only handles changes to already-tracked files.\n}\n\nconst detectChanges = async (tuckDir: string): Promise<FileChange[]> => {\n const files = await getAllTrackedFiles(tuckDir);\n const ignoredPaths = await loadTuckignore(tuckDir);\n const changes: FileChange[] = [];\n\n for (const [, file] of Object.entries(files)) {\n // Skip if in .tuckignore\n if (ignoredPaths.has(file.source)) {\n continue;\n }\n\n const sourcePath = expandPath(file.source);\n\n // Check if source still exists\n if (!(await pathExists(sourcePath))) {\n changes.push({\n path: file.source,\n status: 'deleted',\n source: file.source,\n destination: file.destination,\n });\n continue;\n }\n\n // Check if file has changed compared to stored checksum\n try {\n const sourceChecksum = await getFileChecksum(sourcePath);\n if (sourceChecksum !== file.checksum) {\n changes.push({\n path: file.source,\n status: 'modified',\n source: file.source,\n destination: file.destination,\n });\n }\n } catch {\n changes.push({\n path: file.source,\n status: 'modified',\n source: file.source,\n destination: file.destination,\n });\n }\n }\n\n return changes;\n};\n\n/**\n * Pull from remote if behind, returns info about what happened\n */\nconst pullIfBehind = async (\n tuckDir: string\n): Promise<{ pulled: boolean; behind: number; error?: string }> => {\n const hasRemoteRepo = await hasRemote(tuckDir);\n if (!hasRemoteRepo) {\n return { pulled: false, behind: 0 };\n }\n\n try {\n // Fetch to get latest remote status\n await fetch(tuckDir);\n\n const status = await getStatus(tuckDir);\n\n if (status.behind === 0) {\n return { pulled: false, behind: 0 };\n }\n\n // Pull with rebase to keep history clean\n await pull(tuckDir, { rebase: true });\n\n return { pulled: true, behind: status.behind };\n } catch (error) {\n return {\n pulled: false,\n behind: 0,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n};\n\n/**\n * Detect new dotfiles that are not already tracked\n */\nconst detectNewDotfiles = async (tuckDir: string): Promise<DetectedFile[]> => {\n // Get all detected dotfiles on the system\n const detected = await detectDotfiles();\n\n // Filter out already-tracked files, ignored files, and excluded patterns\n const newFiles: DetectedFile[] = [];\n\n for (const file of detected) {\n // Skip if already tracked\n const tracked = await getTrackedFileBySource(tuckDir, file.path);\n if (tracked) continue;\n\n // Skip if in .tuckignore\n if (await isIgnored(tuckDir, file.path)) continue;\n\n newFiles.push(file);\n }\n\n return newFiles;\n};\n\nconst generateCommitMessage = (result: SyncResult): string => {\n const totalCount = result.modified.length + result.deleted.length;\n const date = new Date().toISOString().split('T')[0];\n\n // Header with emoji and count\n let message = `✨ Update dotfiles\\n\\n`;\n\n // List changes\n const changes: string[] = [];\n\n if (result.modified.length > 0) {\n if (result.modified.length <= 5) {\n // List individual files if 5 or fewer\n changes.push('Modified:');\n result.modified.forEach((file) => {\n changes.push(`• ${file}`);\n });\n } else {\n changes.push(`Modified: ${result.modified.length} files`);\n }\n }\n\n if (result.deleted.length > 0) {\n if (result.deleted.length <= 5) {\n changes.push(result.modified.length > 0 ? '\\nDeleted:' : 'Deleted:');\n result.deleted.forEach((file) => {\n changes.push(`• ${file}`);\n });\n } else {\n changes.push(\n `${result.modified.length > 0 ? '\\n' : ''}Deleted: ${result.deleted.length} files`\n );\n }\n }\n\n if (changes.length > 0) {\n message += changes.join('\\n') + '\\n';\n }\n\n // Footer with branding and metadata\n message += `\\n---\\n`;\n message += `📦 Managed by tuck (tuck.sh) • ${date}`;\n\n if (totalCount > 0) {\n message += ` • ${totalCount} file${totalCount > 1 ? 's' : ''} changed`;\n }\n\n return message;\n};\n\nconst syncFiles = async (\n tuckDir: string,\n changes: FileChange[],\n options: SyncOptions\n): Promise<SyncResult> => {\n const result: SyncResult = {\n modified: [],\n deleted: [],\n };\n\n // Prepare hook options\n const hookOptions: HookOptions = {\n skipHooks: options.noHooks,\n trustHooks: options.trustHooks,\n };\n\n // Run pre-sync hook\n await runPreSyncHook(tuckDir, hookOptions);\n\n // Process each change\n for (const change of changes) {\n const sourcePath = expandPath(change.source);\n const destPath = join(tuckDir, change.destination!);\n\n if (change.status === 'modified') {\n await withSpinner(`Syncing ${change.path}...`, async () => {\n await copyFileOrDir(sourcePath, destPath, { overwrite: true });\n\n // Update checksum in manifest\n const newChecksum = await getFileChecksum(destPath);\n const files = await getAllTrackedFiles(tuckDir);\n const fileId = Object.entries(files).find(([, f]) => f.source === change.source)?.[0];\n\n if (fileId) {\n await updateFileInManifest(tuckDir, fileId, {\n checksum: newChecksum,\n modified: new Date().toISOString(),\n });\n }\n });\n result.modified.push(change.path.split('/').pop() || change.path);\n } else if (change.status === 'deleted') {\n await withSpinner(`Removing ${change.path}...`, async () => {\n // Delete the file from the tuck repository\n await deleteFileOrDir(destPath);\n\n // Remove from manifest\n const files = await getAllTrackedFiles(tuckDir);\n const fileId = Object.entries(files).find(([, f]) => f.source === change.source)?.[0];\n\n if (fileId) {\n await removeFileFromManifest(tuckDir, fileId);\n }\n });\n result.deleted.push(change.path.split('/').pop() || change.path);\n }\n }\n\n // Stage and commit if not --no-commit\n if (!options.noCommit && (result.modified.length > 0 || result.deleted.length > 0)) {\n await withSpinner('Staging changes...', async () => {\n await stageAll(tuckDir);\n });\n\n const message = options.message || generateCommitMessage(result);\n\n await withSpinner('Committing...', async () => {\n result.commitHash = await commit(tuckDir, message);\n });\n }\n\n // Run post-sync hook\n await runPostSyncHook(tuckDir, hookOptions);\n\n return result;\n};\n\n/**\n * Scan modified files for secrets and handle user interaction\n * Returns true if sync should continue, false if aborted\n */\nconst scanAndHandleSecrets = async (\n tuckDir: string,\n changes: FileChange[],\n options: SyncOptions\n): Promise<boolean> => {\n // Skip if force flag is set or scanning is disabled\n if (options.force) {\n return true;\n }\n\n // Check if scanning is enabled in config\n const scanningEnabled = await isSecretScanningEnabled(tuckDir);\n if (!scanningEnabled) {\n return true;\n }\n\n // Get paths of modified files (not deleted)\n const modifiedPaths = changes\n .filter((c) => c.status === 'modified')\n .map((c) => expandPath(c.source));\n\n if (modifiedPaths.length === 0) {\n return true;\n }\n\n // Scan files\n const spinner = prompts.spinner();\n spinner.start('Scanning for secrets...');\n const summary = await scanForSecrets(modifiedPaths, tuckDir);\n spinner.stop('Scan complete');\n\n if (summary.totalSecrets === 0) {\n return true;\n }\n\n // Display results\n displayScanResults(summary);\n\n // Prompt user for action\n const action = await prompts.select('What would you like to do?', [\n { value: 'abort', label: 'Abort sync' },\n { value: 'ignore', label: 'Add files to .tuckignore and skip them' },\n { value: 'proceed', label: 'Proceed anyway (secrets will be committed)' },\n ]);\n\n if (action === 'abort') {\n prompts.cancel('Sync aborted - secrets detected');\n return false;\n }\n\n if (action === 'ignore') {\n // Add files with secrets to .tuckignore\n for (const result of summary.results) {\n const sourcePath = changes.find((c) => expandPath(c.source) === result.path)?.source;\n if (sourcePath) {\n await addToTuckignore(tuckDir, sourcePath);\n logger.dim(`Added ${collapsePath(result.path)} to .tuckignore`);\n }\n }\n // Filter out ignored files from changes list\n // Note: This intentionally mutates the 'changes' array in place so callers see the filtered list\n const filesToRemove = new Set(summary.results.map((r) => r.path));\n changes.splice(\n 0,\n changes.length,\n ...changes.filter((c) => !filesToRemove.has(expandPath(c.source)))\n );\n\n if (changes.length === 0) {\n prompts.log.info('No remaining changes to sync');\n return false;\n }\n return true;\n }\n\n // proceed - continue with warning\n prompts.log.warning('Proceeding with secrets - make sure your repo is private!');\n return true;\n};\n\nconst runInteractiveSync = async (tuckDir: string, options: SyncOptions = {}): Promise<void> => {\n prompts.intro('tuck sync');\n\n // ========== STEP 1: Pull from remote if behind ==========\n if (options.pull !== false && (await hasRemote(tuckDir))) {\n const pullSpinner = prompts.spinner();\n pullSpinner.start('Checking remote for updates...');\n\n const pullResult = await pullIfBehind(tuckDir);\n if (pullResult.error) {\n pullSpinner.stop(`Could not pull: ${pullResult.error}`);\n prompts.log.warning('Continuing with local changes...');\n } else if (pullResult.pulled) {\n pullSpinner.stop(\n `Pulled ${pullResult.behind} commit${pullResult.behind > 1 ? 's' : ''} from remote`\n );\n } else {\n pullSpinner.stop('Up to date with remote');\n }\n }\n\n // ========== STEP 2: Detect changes to tracked files ==========\n const changeSpinner = prompts.spinner();\n changeSpinner.start('Detecting changes to tracked files...');\n const changes = await detectChanges(tuckDir);\n changeSpinner.stop(`Found ${changes.length} changed file${changes.length !== 1 ? 's' : ''}`);\n\n // ========== STEP 2.5: Scan modified files for secrets ==========\n if (changes.length > 0) {\n const shouldContinue = await scanAndHandleSecrets(tuckDir, changes, options);\n if (!shouldContinue) {\n return;\n }\n }\n\n // ========== STEP 3: Scan for new dotfiles (if enabled) ==========\n let newFiles: DetectedFile[] = [];\n if (options.scan !== false) {\n const scanSpinner = prompts.spinner();\n scanSpinner.start('Scanning for new dotfiles...');\n newFiles = await detectNewDotfiles(tuckDir);\n scanSpinner.stop(`Found ${newFiles.length} new dotfile${newFiles.length !== 1 ? 's' : ''}`);\n }\n\n // ========== STEP 4: Handle case where nothing to do ==========\n if (changes.length === 0 && newFiles.length === 0) {\n const gitStatus = await getStatus(tuckDir);\n if (gitStatus.hasChanges) {\n prompts.log.info('No dotfile changes, but repository has uncommitted changes');\n\n const commitAnyway = await prompts.confirm('Commit repository changes?');\n if (commitAnyway) {\n const message = await prompts.text('Commit message:', {\n defaultValue: 'Update dotfiles',\n });\n\n await stageAll(tuckDir);\n const hash = await commit(tuckDir, message);\n prompts.log.success(`Committed: ${hash.slice(0, 7)}`);\n\n // Push if remote exists\n if (options.push !== false && (await hasRemote(tuckDir))) {\n await pushWithSpinner(tuckDir, options);\n }\n }\n } else {\n prompts.log.success('Everything is up to date');\n }\n return;\n }\n\n // ========== STEP 5: Show changes to tracked files ==========\n if (changes.length > 0) {\n console.log();\n console.log(c.bold('Changes to tracked files:'));\n for (const change of changes) {\n if (change.status === 'modified') {\n console.log(c.yellow(` ~ ${change.path}`));\n } else if (change.status === 'deleted') {\n console.log(c.red(` - ${change.path}`));\n }\n }\n }\n\n // ========== STEP 6: Interactive selection for new files ==========\n let filesToTrack: FileToTrack[] = [];\n\n if (newFiles.length > 0) {\n console.log();\n console.log(c.bold(`New dotfiles found (${newFiles.length}):`));\n\n // Group by category for display\n const grouped: Record<string, DetectedFile[]> = {};\n for (const file of newFiles) {\n if (!grouped[file.category]) grouped[file.category] = [];\n grouped[file.category].push(file);\n }\n\n for (const [category, files] of Object.entries(grouped)) {\n const categoryInfo = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n console.log(\n c.cyan(\n ` ${categoryInfo.icon} ${categoryInfo.name}: ${files.length} file${files.length > 1 ? 's' : ''}`\n )\n );\n }\n\n console.log();\n const trackNewFiles = await prompts.confirm(\n 'Would you like to track some of these new files?',\n true\n );\n\n if (trackNewFiles) {\n // Create multiselect options (pre-select non-sensitive files)\n const selectOptions = newFiles.map((f) => ({\n value: f.path,\n label: `${collapsePath(expandPath(f.path))}${f.sensitive ? c.yellow(' [sensitive]') : ''}`,\n hint: f.category,\n }));\n\n const nonSensitiveFiles = newFiles.filter((f) => !f.sensitive);\n const initialValues = nonSensitiveFiles.map((f) => f.path);\n\n const selected = await prompts.multiselect('Select files to track:', selectOptions, {\n initialValues,\n });\n\n filesToTrack = selected.map((path) => ({ path: path as string }));\n }\n }\n\n // ========== STEP 7: Handle large files in tracked changes ==========\n const largeFiles: Array<{ path: string; size: string; sizeBytes: number }> = [];\n\n for (const change of changes) {\n if (change.status !== 'deleted') {\n const expandedPath = expandPath(change.source);\n const sizeCheck = await checkFileSizeThreshold(expandedPath);\n\n if (sizeCheck.warn || sizeCheck.block) {\n largeFiles.push({\n path: change.path,\n size: formatFileSize(sizeCheck.size),\n sizeBytes: sizeCheck.size,\n });\n }\n }\n }\n\n if (largeFiles.length > 0) {\n console.log();\n console.log(c.yellow('Large files detected:'));\n for (const file of largeFiles) {\n console.log(c.yellow(` ${file.path} (${file.size})`));\n }\n console.log();\n console.log(c.dim('GitHub has a 50MB warning and 100MB hard limit.'));\n console.log();\n\n const hasBlockers = largeFiles.some((f) => f.sizeBytes >= SIZE_BLOCK_THRESHOLD);\n\n if (hasBlockers) {\n const action = await prompts.select('Some files exceed 100MB. What would you like to do?', [\n { value: 'ignore', label: 'Add large files to .tuckignore' },\n { value: 'continue', label: 'Try to commit anyway (may fail)' },\n { value: 'cancel', label: 'Cancel sync' },\n ]);\n\n if (action === 'ignore') {\n for (const file of largeFiles) {\n const fullPath = changes.find((c) => c.path === file.path)?.source;\n if (fullPath) {\n await addToTuckignore(tuckDir, fullPath);\n const index = changes.findIndex((c) => c.path === file.path);\n if (index > -1) changes.splice(index, 1);\n }\n }\n prompts.log.success('Added large files to .tuckignore');\n\n if (changes.length === 0 && filesToTrack.length === 0) {\n prompts.log.info('No changes remaining to sync');\n return;\n }\n } else if (action === 'cancel') {\n prompts.cancel('Operation cancelled');\n return;\n }\n } else {\n const action = await prompts.select('Large files detected. What would you like to do?', [\n { value: 'continue', label: 'Continue with sync' },\n { value: 'ignore', label: 'Add to .tuckignore and skip' },\n { value: 'cancel', label: 'Cancel sync' },\n ]);\n\n if (action === 'ignore') {\n for (const file of largeFiles) {\n const fullPath = changes.find((c) => c.path === file.path)?.source;\n if (fullPath) {\n await addToTuckignore(tuckDir, fullPath);\n const index = changes.findIndex((c) => c.path === file.path);\n if (index > -1) changes.splice(index, 1);\n }\n }\n prompts.log.success('Added large files to .tuckignore');\n\n if (changes.length === 0 && filesToTrack.length === 0) {\n prompts.log.info('No changes remaining to sync');\n return;\n }\n } else if (action === 'cancel') {\n prompts.cancel('Operation cancelled');\n return;\n }\n }\n }\n\n // ========== STEP 8: Track new files ==========\n if (filesToTrack.length > 0) {\n console.log();\n await trackFilesWithProgress(filesToTrack, tuckDir, {\n showCategory: true,\n actionVerb: 'Tracking',\n });\n }\n\n // ========== STEP 9: Sync changes to tracked files ==========\n let result: SyncResult = { modified: [], deleted: [] };\n\n if (changes.length > 0) {\n // Generate commit message\n const message =\n options.message ||\n generateCommitMessage({\n modified: changes.filter((c) => c.status === 'modified').map((c) => c.path),\n deleted: changes.filter((c) => c.status === 'deleted').map((c) => c.path),\n });\n\n console.log();\n console.log(c.dim('Commit message:'));\n console.log(\n c.cyan(\n message\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n')\n )\n );\n console.log();\n\n result = await syncFiles(tuckDir, changes, { ...options, message });\n } else if (filesToTrack.length > 0) {\n // Only new files were added, commit them\n if (!options.noCommit) {\n const message =\n options.message ||\n `Add ${filesToTrack.length} new dotfile${filesToTrack.length > 1 ? 's' : ''}`;\n await stageAll(tuckDir);\n result.commitHash = await commit(tuckDir, message);\n }\n }\n\n // ========== STEP 10: Push to remote ==========\n console.log();\n let pushFailed = false;\n\n if (result.commitHash) {\n prompts.log.success(`Committed: ${result.commitHash.slice(0, 7)}`);\n\n if (options.push !== false && (await hasRemote(tuckDir))) {\n pushFailed = !(await pushWithSpinner(tuckDir, options));\n } else if (options.push === false) {\n prompts.log.info(\"Run 'tuck push' when ready to upload\");\n }\n }\n\n // Only show success if no push failure occurred\n if (!pushFailed) {\n prompts.outro('Synced successfully!');\n }\n};\n\n/**\n * Helper to push with spinner and error handling\n */\nconst pushWithSpinner = async (tuckDir: string, _options: SyncOptions): Promise<boolean> => {\n const spinner = prompts.spinner();\n try {\n const status = await getStatus(tuckDir);\n const needsUpstream = !status.tracking;\n const branch = status.branch;\n\n spinner.start('Pushing to remote...');\n await push(tuckDir, {\n setUpstream: needsUpstream,\n branch: needsUpstream ? branch : undefined,\n });\n spinner.stop('Pushed to remote');\n return true;\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n spinner.stop(`Push failed: ${errorMsg}`);\n prompts.log.warning(\"Run 'tuck push' to try again\");\n return false;\n }\n};\n\n/**\n * Run sync programmatically (exported for use by other commands)\n */\nexport const runSync = async (options: SyncOptions = {}): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Always run interactive sync when called programmatically\n await runInteractiveSync(tuckDir, options);\n};\n\nconst runSyncCommand = async (\n messageArg: string | undefined,\n options: SyncOptions\n): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // If no options (except --no-push), run interactive\n if (!messageArg && !options.message && !options.noCommit) {\n await runInteractiveSync(tuckDir, options);\n return;\n }\n\n // Detect changes\n const changes = await detectChanges(tuckDir);\n\n if (changes.length === 0) {\n logger.info('No changes detected');\n return;\n }\n\n // Scan for secrets (non-interactive mode - throw error if found)\n if (!options.force) {\n const scanningEnabled = await isSecretScanningEnabled(tuckDir);\n if (scanningEnabled) {\n const modifiedPaths = changes\n .filter((c) => c.status === 'modified')\n .map((c) => expandPath(c.source));\n\n if (modifiedPaths.length > 0) {\n const summary = await scanForSecrets(modifiedPaths, tuckDir);\n if (summary.totalSecrets > 0) {\n displayScanResults(summary);\n throw new SecretsDetectedError(\n summary.totalSecrets,\n summary.results.map((r) => collapsePath(r.path))\n );\n }\n }\n }\n }\n\n // Show changes\n logger.heading('Changes detected:');\n for (const change of changes) {\n logger.file(change.status === 'modified' ? 'modify' : 'delete', change.path);\n }\n logger.blank();\n\n // Sync\n const message = messageArg || options.message;\n const result = await syncFiles(tuckDir, changes, { ...options, message });\n\n logger.blank();\n logger.success(`Synced ${changes.length} file${changes.length > 1 ? 's' : ''}`);\n\n if (result.commitHash) {\n logger.info(`Commit: ${result.commitHash.slice(0, 7)}`);\n\n // Push by default unless --no-push\n // Commander converts --no-push to push: false, default is push: true\n if (options.push !== false && (await hasRemote(tuckDir))) {\n await withSpinner('Pushing to remote...', async () => {\n await push(tuckDir);\n });\n logger.success('Pushed to remote');\n } else if (options.push === false) {\n logger.info(\"Run 'tuck push' when ready to upload\");\n }\n }\n};\n\nexport const syncCommand = new Command('sync')\n .description(\n 'Sync all dotfile changes (pull, detect changes, scan for new files, track, commit, push)'\n )\n .argument('[message]', 'Commit message')\n .option('-m, --message <msg>', 'Commit message')\n // TODO: --all and --amend are planned for a future version\n // .option('-a, --all', 'Sync all tracked files, not just changed')\n // .option('--amend', 'Amend previous commit')\n .option('--no-commit', \"Stage changes but don't commit\")\n .option('--no-push', \"Commit but don't push to remote\")\n .option('--no-pull', \"Don't pull from remote first\")\n .option('--no-scan', \"Don't scan for new dotfiles\")\n .option('--no-hooks', 'Skip execution of pre/post sync hooks')\n .option('--trust-hooks', 'Trust and run hooks without confirmation (use with caution)')\n .option('-f, --force', 'Skip secret scanning (not recommended)')\n .action(async (messageArg: string | undefined, options: SyncOptions) => {\n await runSyncCommand(messageArg, options);\n });\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport {\n initCommand,\n addCommand,\n removeCommand,\n syncCommand,\n pushCommand,\n pullCommand,\n restoreCommand,\n statusCommand,\n listCommand,\n diffCommand,\n configCommand,\n applyCommand,\n undoCommand,\n scanCommand,\n secretsCommand,\n} from './commands/index.js';\nimport { handleError } from './errors.js';\nimport { VERSION, DESCRIPTION } from './constants.js';\nimport { checkForUpdates } from './lib/updater.js';\nimport { customHelp, miniBanner } from './ui/banner.js';\nimport { getTuckDir, pathExists } from './lib/paths.js';\nimport { loadManifest } from './lib/manifest.js';\nimport { getStatus } from './lib/git.js';\n\nconst program = new Command();\n\nprogram\n .name('tuck')\n .description(DESCRIPTION)\n .version(VERSION, '-v, --version', 'Display version number')\n .configureOutput({\n outputError: (str, write) => write(chalk.red(str)),\n })\n .addHelpText('before', customHelp(VERSION))\n .helpOption('-h, --help', 'Display this help message')\n .showHelpAfterError(false);\n\n// Register commands\nprogram.addCommand(initCommand);\nprogram.addCommand(addCommand);\nprogram.addCommand(removeCommand);\nprogram.addCommand(syncCommand);\nprogram.addCommand(pushCommand);\nprogram.addCommand(pullCommand);\nprogram.addCommand(restoreCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(listCommand);\nprogram.addCommand(diffCommand);\nprogram.addCommand(configCommand);\nprogram.addCommand(applyCommand);\nprogram.addCommand(undoCommand);\nprogram.addCommand(scanCommand);\nprogram.addCommand(secretsCommand);\n\n// Default action when no command is provided\nconst runDefaultAction = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Check if tuck is initialized\n if (!(await pathExists(tuckDir))) {\n miniBanner();\n console.log(chalk.bold('Get started with tuck:\\n'));\n console.log(chalk.cyan(' tuck init') + chalk.dim(' - Set up tuck and create a GitHub repo'));\n console.log(chalk.cyan(' tuck scan') + chalk.dim(' - Find dotfiles to track'));\n console.log();\n console.log(chalk.dim('On a new machine:'));\n console.log(chalk.cyan(' tuck apply <username>') + chalk.dim(' - Apply your dotfiles'));\n console.log();\n return;\n }\n\n // Load manifest to check status\n try {\n const manifest = await loadManifest(tuckDir);\n const trackedCount = Object.keys(manifest.files).length;\n const gitStatus = await getStatus(tuckDir);\n\n miniBanner();\n console.log(chalk.bold('Status:\\n'));\n\n // Show tracked files count\n console.log(` Tracked files: ${chalk.cyan(trackedCount.toString())}`);\n\n // Show git status\n const pendingChanges = gitStatus.modified.length + gitStatus.staged.length;\n if (pendingChanges > 0) {\n console.log(` Pending changes: ${chalk.yellow(pendingChanges.toString())}`);\n } else {\n console.log(` Pending changes: ${chalk.dim('none')}`);\n }\n\n // Show remote status\n if (gitStatus.ahead > 0) {\n console.log(` Commits to push: ${chalk.yellow(gitStatus.ahead.toString())}`);\n }\n\n console.log();\n\n // Show what to do next\n console.log(chalk.bold('Next steps:\\n'));\n\n if (trackedCount === 0) {\n console.log(chalk.cyan(' tuck scan') + chalk.dim(' - Find dotfiles to track'));\n console.log(chalk.cyan(' tuck add <file>') + chalk.dim(' - Track a specific file'));\n } else if (pendingChanges > 0) {\n console.log(chalk.cyan(' tuck sync') + chalk.dim(' - Commit and push your changes'));\n console.log(chalk.cyan(' tuck diff') + chalk.dim(' - Preview what changed'));\n } else if (gitStatus.ahead > 0) {\n console.log(chalk.cyan(' tuck push') + chalk.dim(' - Push commits to GitHub'));\n } else {\n console.log(chalk.dim(' All synced! Your dotfiles are up to date.'));\n console.log();\n console.log(chalk.cyan(' tuck scan') + chalk.dim(' - Find more dotfiles to track'));\n console.log(chalk.cyan(' tuck list') + chalk.dim(' - See tracked files'));\n }\n\n console.log();\n } catch {\n // Manifest load failed, treat as not initialized\n miniBanner();\n console.log(chalk.yellow('Tuck directory exists but may be corrupted.'));\n console.log(chalk.dim('Run `tuck init` to reinitialize.'));\n console.log();\n }\n};\n\n// Check if no command provided\nconst hasCommand = process.argv\n .slice(2)\n .some((arg) => !arg.startsWith('-') && arg !== '--help' && arg !== '-h');\n\n// Global error handling\nprocess.on('uncaughtException', handleError);\nprocess.on('unhandledRejection', (reason) => {\n handleError(reason instanceof Error ? reason : new Error(String(reason)));\n});\n\n// Check if this is a help or version request (skip update check for these)\nconst isHelpOrVersion =\n process.argv.includes('--help') ||\n process.argv.includes('-h') ||\n process.argv.includes('--version') ||\n process.argv.includes('-v');\n\n// Main execution\nconst main = async (): Promise<void> => {\n // Check for updates (skipped for help/version)\n if (!isHelpOrVersion) {\n await checkForUpdates();\n }\n\n // Parse and execute\n if (!hasCommand && !isHelpOrVersion) {\n await runDefaultAction();\n } else {\n await program.parseAsync(process.argv);\n }\n};\n\nmain().catch(handleError);\n","import { Command } from 'commander';\nimport { join } from 'path';\nimport { writeFile } from 'fs/promises';\nimport { ensureDir } from 'fs-extra';\nimport { banner, nextSteps, prompts, withSpinner, logger, colors as c } from '../ui/index.js';\nimport {\n getTuckDir,\n getManifestPath,\n getConfigPath,\n getFilesDir,\n getCategoryDir,\n pathExists,\n collapsePath,\n} from '../lib/paths.js';\nimport { saveConfig } from '../lib/config.js';\nimport { createManifest } from '../lib/manifest.js';\nimport type { TuckManifest, RemoteConfig } from '../types.js';\nimport {\n initRepo,\n addRemote,\n cloneRepo,\n setDefaultBranch,\n stageAll,\n commit,\n push,\n} from '../lib/git.js';\nimport {\n setupProvider,\n detectProviderFromUrl,\n type ProviderSetupResult,\n} from '../lib/providerSetup.js';\nimport { getProvider, describeProviderConfig, buildRemoteConfig } from '../lib/providers/index.js';\nimport {\n isGhInstalled,\n isGhAuthenticated,\n getAuthenticatedUser,\n createRepo,\n getPreferredRepoUrl,\n getPreferredRemoteProtocol,\n findDotfilesRepo,\n ghCloneRepo,\n checkSSHKeys,\n testSSHConnection,\n getSSHKeyInstructions,\n getFineGrainedTokenInstructions,\n getClassicTokenInstructions,\n getGitHubCLIInstallInstructions,\n storeGitHubCredentials,\n detectTokenType,\n configureGitCredentialHelper,\n testStoredCredentials,\n diagnoseAuthIssue,\n MIN_GITHUB_TOKEN_LENGTH,\n GITHUB_TOKEN_PREFIXES,\n} from '../lib/github.js';\nimport { detectDotfiles, DetectedFile, DETECTION_CATEGORIES } from '../lib/detect.js';\nimport { copy } from 'fs-extra';\nimport { tmpdir } from 'os';\nimport { readFile, rm } from 'fs/promises';\nimport { AlreadyInitializedError } from '../errors.js';\nimport { CATEGORIES } from '../constants.js';\nimport { defaultConfig } from '../schemas/config.schema.js';\nimport type { InitOptions } from '../types.js';\nimport { trackFilesWithProgress, type FileToTrack } from '../lib/fileTracking.js';\n\nconst GITIGNORE_TEMPLATE = `# OS generated files\n.DS_Store\n.DS_Store?\n._*\n.Spotlight-V100\n.Trashes\nehthumbs.db\nThumbs.db\n\n# Backup files\n*.bak\n*.backup\n*~\n\n# Secret files (add patterns for files you want to exclude)\n# *.secret\n# .env.local\n`;\n\n/**\n * Track selected files with beautiful progress display\n */\nconst trackFilesWithProgressInit = async (\n selectedPaths: string[],\n tuckDir: string\n): Promise<number> => {\n // Convert paths to FileToTrack\n const filesToTrack: FileToTrack[] = selectedPaths.map((path) => ({\n path,\n }));\n\n // Use the shared tracking utility\n const result = await trackFilesWithProgress(filesToTrack, tuckDir, {\n showCategory: true,\n actionVerb: 'Tracking',\n });\n\n return result.succeeded;\n};\n\nconst README_TEMPLATE = (machine?: string) => `# Dotfiles\n\nManaged with [tuck](https://github.com/Pranav-Karra-3301/tuck) - Modern Dotfiles Manager\n\n${machine ? `## Machine: ${machine}\\n` : ''}\n\n## Quick Start\n\n\\`\\`\\`bash\n# Restore dotfiles to a new machine\ntuck init --from <this-repo-url>\n\n# Or clone and restore manually\ngit clone <this-repo-url> ~/.tuck\ntuck restore --all\n\\`\\`\\`\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| \\`tuck add <paths>\\` | Track new dotfiles |\n| \\`tuck sync\\` | Sync changes to repository |\n| \\`tuck push\\` | Push to remote |\n| \\`tuck pull\\` | Pull from remote |\n| \\`tuck restore\\` | Restore dotfiles to system |\n| \\`tuck status\\` | Show tracking status |\n| \\`tuck list\\` | List tracked files |\n\n## Structure\n\n\\`\\`\\`\n.tuck/\n├── files/ # Tracked dotfiles organized by category\n│ ├── shell/ # Shell configs (.zshrc, .bashrc, etc.)\n│ ├── git/ # Git configs (.gitconfig, etc.)\n│ ├── editors/ # Editor configs (nvim, vim, etc.)\n│ ├── terminal/ # Terminal configs (tmux, alacritty, etc.)\n│ └── misc/ # Other dotfiles\n├── .tuckmanifest.json # Tracks all managed files\n└── .tuckrc.json # Tuck configuration\n\\`\\`\\`\n`;\n\n/**\n * Validates a GitHub repository URL (HTTPS or SSH format) and checks for owner/repo pattern\n * @param value The URL to validate\n * @returns undefined if valid, or an error message string if invalid\n */\nconst validateGitHubUrl = (value: string): string | undefined => {\n if (!value) return 'Repository URL is required';\n\n const isGitHubHttps = value.startsWith('https://github.com/');\n const isGitHubSsh = value.startsWith('git@github.com:');\n\n if (!isGitHubHttps && !isGitHubSsh) {\n return 'Please enter a valid GitHub URL';\n }\n\n // Validate URL contains owner/repo pattern\n if (isGitHubHttps) {\n // HTTPS format: https://github.com/owner/repo[.git]\n const pathPart = value.substring('https://github.com/'.length);\n if (!pathPart.includes('/') || pathPart === '/') {\n return 'GitHub URL must include owner and repository name (e.g., https://github.com/owner/repo)';\n }\n } else if (isGitHubSsh) {\n // SSH format: git@github.com:owner/repo[.git]\n const pathPart = value.substring('git@github.com:'.length);\n if (!pathPart.includes('/') || pathPart === '/') {\n return 'GitHub URL must include owner and repository name (e.g., git@github.com:owner/repo.git)';\n }\n }\n\n return undefined;\n};\n\n/**\n * Validate any Git repository URL (not just GitHub)\n * Used when cloning existing repositories that may be hosted anywhere\n */\nconst validateGitUrl = (value: string): string | undefined => {\n if (!value) return 'Repository URL is required';\n\n const trimmed = value.trim();\n\n // Check for common Git URL patterns\n const isHttps = /^https?:\\/\\/.+\\/.+/.test(trimmed); // Must have at least host/path\n const isSshScp = /^[^@]+@[^@:]+:[^:]+\\/.+/.test(trimmed); // e.g. git@host:user/repo.git\n const isSshUrl = /^ssh:\\/\\/.+\\/.+/.test(trimmed); // e.g. ssh://git@host/user/repo.git\n\n if (!isHttps && !isSshScp && !isSshUrl) {\n return 'Please enter a valid Git repository URL (HTTPS or SSH format)';\n }\n\n return undefined;\n};\n\nconst createDirectoryStructure = async (tuckDir: string): Promise<void> => {\n // Create main directories\n await ensureDir(tuckDir);\n await ensureDir(getFilesDir(tuckDir));\n\n // Create category directories\n for (const category of Object.keys(CATEGORIES)) {\n await ensureDir(getCategoryDir(tuckDir, category));\n }\n};\n\nconst createDefaultFiles = async (tuckDir: string, machine?: string): Promise<void> => {\n // Create .gitignore only if it doesn't exist\n const gitignorePath = join(tuckDir, '.gitignore');\n if (!(await pathExists(gitignorePath))) {\n await writeFile(gitignorePath, GITIGNORE_TEMPLATE, 'utf-8');\n }\n\n // Create README.md only if it doesn't exist\n const readmePath = join(tuckDir, 'README.md');\n if (!(await pathExists(readmePath))) {\n await writeFile(readmePath, README_TEMPLATE(machine), 'utf-8');\n }\n};\n\nconst initFromScratch = async (\n tuckDir: string,\n options: { remote?: string; bare?: boolean; remoteConfig?: RemoteConfig }\n): Promise<void> => {\n // Check if already initialized\n if (await pathExists(getManifestPath(tuckDir))) {\n throw new AlreadyInitializedError(tuckDir);\n }\n\n // Create directory structure\n await withSpinner('Creating directory structure...', async () => {\n await createDirectoryStructure(tuckDir);\n });\n\n // Initialize git repository\n await withSpinner('Initializing git repository...', async () => {\n await initRepo(tuckDir);\n await setDefaultBranch(tuckDir, 'main');\n });\n\n // Create manifest\n await withSpinner('Creating manifest...', async () => {\n const hostname = (await import('os')).hostname();\n await createManifest(tuckDir, hostname);\n });\n\n // Create config with remote settings\n await withSpinner('Creating configuration...', async () => {\n await saveConfig(\n {\n ...defaultConfig,\n repository: { ...defaultConfig.repository, path: tuckDir },\n remote: options.remoteConfig || defaultConfig.remote,\n },\n tuckDir\n );\n });\n\n // Create default files unless --bare\n if (!options.bare) {\n await withSpinner('Creating default files...', async () => {\n const hostname = (await import('os')).hostname();\n await createDefaultFiles(tuckDir, hostname);\n });\n }\n\n // Add remote if provided\n if (options.remote) {\n await withSpinner('Adding remote...', async () => {\n await addRemote(tuckDir, 'origin', options.remote!);\n });\n }\n};\n\ninterface GitHubSetupResult {\n remoteUrl: string | null;\n pushed: boolean;\n}\n\n/**\n * Set up alternative authentication (SSH or tokens)\n */\nconst setupAlternativeAuth = async (tuckDir: string): Promise<GitHubSetupResult> => {\n console.log();\n prompts.log.info(\"GitHub CLI not available. Let's set up authentication another way.\");\n console.log();\n\n // Check for existing credentials and test them\n const credTest = await testStoredCredentials();\n if (credTest.valid && credTest.username) {\n prompts.log.success(`Found existing valid credentials for ${credTest.username}`);\n const useExisting = await prompts.confirm('Use these credentials?', true);\n if (useExisting) {\n // Credentials work - ask for repo URL\n return await promptForManualRepoUrl(tuckDir, credTest.username);\n }\n } else if (credTest.username && credTest.reason) {\n // Had credentials but they failed\n const diagnosis = await diagnoseAuthIssue();\n prompts.log.warning(diagnosis.issue);\n for (const suggestion of diagnosis.suggestions) {\n console.log(c.muted(` ${suggestion}`));\n }\n console.log();\n }\n\n // Check for existing SSH keys\n const sshInfo = await checkSSHKeys();\n const sshConnection = sshInfo.exists ? await testSSHConnection() : { success: false };\n\n // Build auth method options\n const authOptions: Array<{ value: string; label: string; hint: string }> = [];\n\n if (sshInfo.exists && sshConnection.success) {\n authOptions.push({\n value: 'ssh-existing',\n label: 'Use existing SSH key',\n hint: `Connected as ${sshConnection.username}`,\n });\n }\n\n authOptions.push(\n {\n value: 'gh-cli',\n label: 'Install GitHub CLI (recommended)',\n hint: 'Easiest option - automatic repo creation',\n },\n {\n value: 'ssh-new',\n label: 'Set up SSH key',\n hint: sshInfo.exists ? 'Configure existing key' : 'Generate new SSH key',\n },\n {\n value: 'fine-grained',\n label: 'Use Fine-grained Token',\n hint: 'More secure - limited permissions',\n },\n {\n value: 'classic',\n label: 'Use Classic Token',\n hint: 'Broader access - simpler setup',\n },\n {\n value: 'skip',\n label: 'Skip for now',\n hint: 'Set up authentication later',\n }\n );\n\n const authMethod = await prompts.select('Choose an authentication method:', authOptions);\n\n if (authMethod === 'skip') {\n return { remoteUrl: null, pushed: false };\n }\n\n if (authMethod === 'gh-cli') {\n // Show GitHub CLI install instructions\n console.log();\n prompts.note(getGitHubCLIInstallInstructions(), 'GitHub CLI Installation');\n console.log();\n prompts.log.info('After installing and authenticating, run `tuck init` again');\n prompts.log.info('Or continue with token-based authentication below');\n\n const continueWithToken = await prompts.confirm('Set up token authentication instead?', true);\n if (!continueWithToken) {\n return { remoteUrl: null, pushed: false };\n }\n // Fall through to token setup\n return await setupTokenAuth(tuckDir);\n }\n\n if (authMethod === 'ssh-existing') {\n // SSH key already works - just need repo URL\n prompts.log.success(`SSH authenticated as ${sshConnection.username}`);\n return await promptForManualRepoUrl(tuckDir, sshConnection.username, 'ssh');\n }\n\n if (authMethod === 'ssh-new') {\n // Show SSH setup instructions\n console.log();\n prompts.note(getSSHKeyInstructions(), 'SSH Key Setup');\n console.log();\n\n if (sshInfo.exists) {\n prompts.log.info(`Found existing SSH key at ${sshInfo.path}`);\n if (sshInfo.publicKey) {\n console.log();\n prompts.log.info('Your public key (copy this to GitHub):');\n console.log(c.brand(sshInfo.publicKey));\n console.log();\n }\n }\n\n const sshReady = await prompts.confirm('Have you added your SSH key to GitHub?');\n if (sshReady) {\n // Test connection\n const testSpinner = prompts.spinner();\n testSpinner.start('Testing SSH connection...');\n const testResult = await testSSHConnection();\n if (testResult.success) {\n testSpinner.stop(`SSH authenticated as ${testResult.username}`);\n return await promptForManualRepoUrl(tuckDir, testResult.username, 'ssh');\n } else {\n testSpinner.stop('SSH connection failed');\n prompts.log.warning('Could not connect to GitHub via SSH');\n prompts.log.info('Make sure you added the public key and try again');\n\n const useTokenInstead = await prompts.confirm('Use token authentication instead?', true);\n if (useTokenInstead) {\n return await setupTokenAuth(tuckDir);\n }\n }\n }\n return { remoteUrl: null, pushed: false };\n }\n\n if (authMethod === 'fine-grained' || authMethod === 'classic') {\n return await setupTokenAuth(\n tuckDir,\n authMethod === 'fine-grained' ? 'fine-grained' : 'classic'\n );\n }\n\n return { remoteUrl: null, pushed: false };\n};\n\n/**\n * Set up token-based authentication\n */\nconst setupTokenAuth = async (\n tuckDir: string,\n preferredType?: 'fine-grained' | 'classic'\n): Promise<GitHubSetupResult> => {\n const tokenType =\n preferredType ??\n (await prompts.select('Which type of token?', [\n {\n value: 'fine-grained',\n label: 'Fine-grained Token (recommended)',\n hint: 'Limited permissions, more secure',\n },\n {\n value: 'classic',\n label: 'Classic Token',\n hint: 'Full repo access, simpler',\n },\n ]));\n\n // Show instructions for the selected token type\n console.log();\n if (tokenType === 'fine-grained') {\n prompts.note(getFineGrainedTokenInstructions(), 'Fine-grained Token Setup');\n } else {\n prompts.note(getClassicTokenInstructions(), 'Classic Token Setup');\n }\n console.log();\n\n // Ask for username\n const username = await prompts.text('Enter your GitHub username:', {\n validate: (value) => {\n if (!value) return 'Username is required';\n // GitHub username rules: 1-39 characters total, start with alphanumeric, may contain hyphens\n // (no consecutive or trailing hyphens).\n if (!/^[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}$/.test(value)) {\n return 'Invalid GitHub username (must start with a letter or number, be 1-39 characters, and may include hyphens but not consecutively or at the end).';\n }\n return undefined;\n },\n });\n\n // Ask for token\n const token = await prompts.password('Paste your token (hidden):');\n\n if (!token) {\n prompts.log.warning('No token provided');\n return { remoteUrl: null, pushed: false };\n }\n\n // Basic token format validation\n if (token.length < MIN_GITHUB_TOKEN_LENGTH) {\n prompts.log.error('Invalid token: Token appears too short');\n return { remoteUrl: null, pushed: false };\n }\n\n // Check if token starts with expected GitHub token prefixes\n const hasValidPrefix = GITHUB_TOKEN_PREFIXES.some((prefix) => token.startsWith(prefix));\n\n if (!hasValidPrefix) {\n const prefixList = GITHUB_TOKEN_PREFIXES.join(', ');\n prompts.log.warning(\n `Warning: Token does not start with a recognized GitHub prefix (${prefixList}). ` +\n 'This may cause authentication to fail.'\n );\n\n const proceedWithUnrecognizedToken = await prompts.confirm(\n 'The value you entered does not look like a typical GitHub personal access token. ' +\n 'Are you sure this is a GitHub token and not, for example, a password or another secret?'\n );\n\n if (!proceedWithUnrecognizedToken) {\n prompts.log.error(\n 'Aborting setup to avoid storing a value that may not be a GitHub token. ' +\n 'Please generate a GitHub personal access token and try again.'\n );\n return { remoteUrl: null, pushed: false };\n }\n }\n\n // Auto-detect token type\n const detectedType = detectTokenType(token);\n const finalType =\n detectedType !== 'unknown' ? detectedType : (tokenType as 'fine-grained' | 'classic');\n\n if (detectedType !== 'unknown' && detectedType !== tokenType) {\n prompts.log.info(\n `Detected ${detectedType === 'fine-grained' ? 'fine-grained' : 'classic'} token`\n );\n }\n\n // Store credentials securely\n const storeSpinner = prompts.spinner();\n storeSpinner.start('Storing credentials securely...');\n\n try {\n await storeGitHubCredentials(username, token, finalType);\n storeSpinner.stop('Credentials stored');\n prompts.log.success('Authentication configured successfully');\n } catch (error) {\n storeSpinner.stop('Failed to store credentials');\n prompts.log.warning(\n `Could not store credentials: ${error instanceof Error ? error.message : String(error)}`\n );\n prompts.log.info('You may be prompted for credentials when pushing');\n }\n\n // Configure git credential helper (best-effort; Git can still prompt for credentials if this fails)\n await configureGitCredentialHelper().catch((error) => {\n const errorMsg = error instanceof Error ? error.message : String(error);\n logger?.debug?.(`Failed to configure git credential helper (non-fatal): ${errorMsg}`);\n });\n\n return await promptForManualRepoUrl(tuckDir, username, 'https');\n};\n\n/**\n * Prompt user for a repository URL and configure remote\n */\nconst promptForManualRepoUrl = async (\n tuckDir: string,\n username?: string,\n preferredProtocol: 'ssh' | 'https' = 'https'\n): Promise<GitHubSetupResult> => {\n const suggestedName = 'dotfiles';\n const exampleUrl =\n preferredProtocol === 'ssh'\n ? `git@github.com:${username || 'username'}/${suggestedName}.git`\n : `https://github.com/${username || 'username'}/${suggestedName}.git`;\n\n console.log();\n prompts.note(\n `Create a repository on GitHub:\\n\\n` +\n `1. Go to: https://github.com/new\\n` +\n `2. Name: ${suggestedName}\\n` +\n `3. Visibility: Private (recommended)\\n` +\n `4. Do NOT add README or .gitignore\\n` +\n `5. Click \"Create repository\"\\n` +\n `6. Copy the ${preferredProtocol.toUpperCase()} URL`,\n 'Manual Repository Setup'\n );\n console.log();\n\n const hasRepo = await prompts.confirm('Have you created the repository?');\n if (!hasRepo) {\n prompts.log.info('Create a repository first, then run `tuck init` again');\n return { remoteUrl: null, pushed: false };\n }\n\n const repoUrl = await prompts.text('Paste the repository URL:', {\n placeholder: exampleUrl,\n validate: validateGitHubUrl,\n });\n\n // Add remote\n try {\n await addRemote(tuckDir, 'origin', repoUrl);\n prompts.log.success('Remote configured');\n return { remoteUrl: repoUrl, pushed: false };\n } catch (error) {\n prompts.log.error(\n `Failed to add remote: ${error instanceof Error ? error.message : String(error)}`\n );\n return { remoteUrl: null, pushed: false };\n }\n};\n\nconst setupGitHubRepo = async (tuckDir: string): Promise<GitHubSetupResult> => {\n // Check if GitHub CLI is available\n const ghInstalled = await isGhInstalled();\n if (!ghInstalled) {\n // Offer alternative authentication methods\n return await setupAlternativeAuth(tuckDir);\n }\n\n const ghAuth = await isGhAuthenticated();\n if (!ghAuth) {\n prompts.log.info('GitHub CLI is installed but not authenticated');\n\n const authChoice = await prompts.select('How would you like to authenticate?', [\n {\n value: 'gh-login',\n label: 'Run `gh auth login` now',\n hint: 'Opens browser to authenticate',\n },\n {\n value: 'alternative',\n label: 'Use alternative method',\n hint: 'SSH key or personal access token',\n },\n {\n value: 'skip',\n label: 'Skip for now',\n hint: 'Set up authentication later',\n },\n ]);\n\n if (authChoice === 'skip') {\n return { remoteUrl: null, pushed: false };\n }\n\n if (authChoice === 'alternative') {\n return await setupAlternativeAuth(tuckDir);\n }\n\n // Run gh auth login\n prompts.log.info('Please complete the authentication in your browser...');\n try {\n const { execFile } = await import('child_process');\n const { promisify } = await import('util');\n const execFileAsync = promisify(execFile);\n await execFileAsync('gh', ['auth', 'login', '--web']);\n\n // Re-check auth status\n if (!(await isGhAuthenticated())) {\n prompts.log.warning('Authentication may have failed');\n return await setupAlternativeAuth(tuckDir);\n }\n } catch (error) {\n prompts.log.warning(\n `Authentication failed: ${error instanceof Error ? error.message : String(error)}`\n );\n const useAlt = await prompts.confirm('Try alternative authentication?', true);\n if (useAlt) {\n return await setupAlternativeAuth(tuckDir);\n }\n return { remoteUrl: null, pushed: false };\n }\n }\n\n // Get authenticated user\n const user = await getAuthenticatedUser();\n prompts.log.success(`Detected GitHub account: ${user.login}`);\n\n // Ask if they want to auto-create repo\n const createGhRepo = await prompts.confirm('Create a GitHub repository automatically?', true);\n\n if (!createGhRepo) {\n return { remoteUrl: null, pushed: false };\n }\n\n // Ask for repo name\n const repoName = await prompts.text('Repository name:', {\n defaultValue: 'dotfiles',\n placeholder: 'dotfiles',\n validate: (value) => {\n if (!value) return 'Repository name is required';\n if (!/^[a-zA-Z0-9._-]+$/.test(value)) {\n return 'Invalid repository name';\n }\n return undefined;\n },\n });\n\n // Ask for visibility\n const visibility = await prompts.select('Repository visibility:', [\n { value: 'private', label: 'Private (recommended)', hint: 'Only you can see it' },\n { value: 'public', label: 'Public', hint: 'Anyone can see it' },\n ]);\n\n // Create the repository\n let repo;\n try {\n const spinner = prompts.spinner();\n spinner.start(`Creating repository ${user.login}/${repoName}...`);\n\n repo = await createRepo({\n name: repoName,\n description: 'My dotfiles managed with tuck',\n isPrivate: visibility === 'private',\n });\n\n spinner.stop(`Repository created: ${repo.fullName}`);\n } catch (error) {\n prompts.log.error(\n `Failed to create repository: ${error instanceof Error ? error.message : String(error)}`\n );\n return { remoteUrl: null, pushed: false };\n }\n\n // Get the remote URL in preferred format\n const remoteUrl = await getPreferredRepoUrl(repo);\n\n // Add as remote\n await addRemote(tuckDir, 'origin', remoteUrl);\n prompts.log.success('Remote origin configured');\n\n // Ask to push initial commit\n const shouldPush = await prompts.confirm('Push initial commit to GitHub?', true);\n\n if (shouldPush) {\n try {\n const spinner = prompts.spinner();\n spinner.start('Creating initial commit...');\n\n await stageAll(tuckDir);\n await commit(tuckDir, 'Initial commit: tuck dotfiles setup');\n\n spinner.stop('Initial commit created');\n\n spinner.start('Pushing to GitHub...');\n await push(tuckDir, { remote: 'origin', branch: 'main', setUpstream: true });\n spinner.stop('Pushed to GitHub');\n\n prompts.note(\n `Your dotfiles are now at:\\n${repo.url}\\n\\nOn a new machine, run:\\ntuck apply ${user.login}`,\n 'Success'\n );\n\n return { remoteUrl, pushed: true };\n } catch (error) {\n prompts.log.error(\n `Failed to push: ${error instanceof Error ? error.message : String(error)}`\n );\n return { remoteUrl, pushed: false };\n }\n }\n\n return { remoteUrl, pushed: false };\n};\n\ntype RepositoryAnalysis =\n | { type: 'valid-tuck'; manifest: TuckManifest }\n | { type: 'plain-dotfiles'; files: DetectedFile[] }\n | { type: 'messed-up'; reason: string };\n\n/**\n * Analyze a cloned repository to determine its state\n */\nconst analyzeRepository = async (repoDir: string): Promise<RepositoryAnalysis> => {\n const manifestPath = join(repoDir, '.tuckmanifest.json');\n\n // Check for valid tuck manifest\n if (await pathExists(manifestPath)) {\n try {\n const content = await readFile(manifestPath, 'utf-8');\n const manifest = JSON.parse(content) as TuckManifest;\n\n // Validate manifest has files\n if (manifest.files && Object.keys(manifest.files).length > 0) {\n return { type: 'valid-tuck', manifest };\n }\n\n // Manifest exists but is empty\n return { type: 'messed-up', reason: 'Manifest exists but contains no tracked files' };\n } catch {\n return { type: 'messed-up', reason: 'Manifest file is corrupted or invalid' };\n }\n }\n\n // No manifest - check for common dotfiles in the files directory or root\n const filesDir = join(repoDir, 'files');\n const hasFilesDir = await pathExists(filesDir);\n\n // Look for common dotfile patterns in the repo\n const commonPatterns = [\n '.zshrc',\n '.bashrc',\n '.bash_profile',\n '.gitconfig',\n '.vimrc',\n '.tmux.conf',\n '.profile',\n 'zshrc',\n 'bashrc',\n 'gitconfig',\n 'vimrc',\n ];\n\n const foundFiles: string[] = [];\n\n // Check in files directory if it exists\n if (hasFilesDir) {\n const { readdir } = await import('fs/promises');\n try {\n const categories = await readdir(filesDir);\n for (const category of categories) {\n const categoryPath = join(filesDir, category);\n const categoryStats = await import('fs/promises').then((fs) =>\n fs.stat(categoryPath).catch(() => null)\n );\n if (categoryStats?.isDirectory()) {\n const files = await readdir(categoryPath);\n foundFiles.push(...files);\n }\n }\n } catch {\n // Ignore errors\n }\n }\n\n // Check root directory\n const { readdir } = await import('fs/promises');\n try {\n const rootFiles = await readdir(repoDir);\n for (const file of rootFiles) {\n if (commonPatterns.some((p) => file.includes(p) || file.startsWith('.'))) {\n foundFiles.push(file);\n }\n }\n } catch {\n // Ignore errors\n }\n\n // Filter to meaningful dotfiles (not just .git, README, etc.)\n const meaningfulFiles = foundFiles.filter(\n (f) => !['README.md', 'README', '.git', '.gitignore', 'LICENSE', '.tuckrc.json'].includes(f)\n );\n\n if (meaningfulFiles.length > 0) {\n // Run detection on user's system and show what would be tracked\n const detectedOnSystem = await detectDotfiles();\n return { type: 'plain-dotfiles', files: detectedOnSystem };\n }\n\n // Check if repo is essentially empty (only has README, .git, etc.)\n const { readdir: rd } = await import('fs/promises');\n try {\n const allFiles = await rd(repoDir);\n const nonEssentialFiles = allFiles.filter(\n (f) => !['.git', 'README.md', 'README', 'LICENSE', '.gitignore'].includes(f)\n );\n if (nonEssentialFiles.length === 0) {\n return { type: 'messed-up', reason: 'Repository is empty (only contains README or license)' };\n }\n } catch {\n // Ignore\n }\n\n return { type: 'messed-up', reason: 'Repository does not contain recognizable dotfiles' };\n};\n\ninterface ImportResult {\n success: boolean;\n filesInRepo: number; // Files imported to ~/.tuck\n filesApplied: number; // Files applied to system (0 if user declined)\n remoteUrl?: string;\n}\n\n/**\n * Import an existing GitHub dotfiles repository\n */\nconst importExistingRepo = async (\n tuckDir: string,\n repoName: string,\n analysis: RepositoryAnalysis,\n repoDir: string\n): Promise<ImportResult> => {\n const { getPreferredRemoteProtocol } = await import('../lib/github.js');\n const protocol = await getPreferredRemoteProtocol();\n const remoteUrl =\n protocol === 'ssh' ? `git@github.com:${repoName}.git` : `https://github.com/${repoName}.git`;\n\n if (analysis.type === 'valid-tuck') {\n // Scenario A: Valid tuck repository - import only (NO auto-apply)\n // BREAKING CHANGE: Files are no longer automatically applied when cloning a tuck repository.\n // This is a safer default that prevents accidental overwrites of existing configurations.\n // User should run 'tuck apply' or 'tuck restore' manually when ready.\n prompts.log.step('Importing tuck repository...');\n\n // Copy the entire repo to tuck directory\n const spinner = prompts.spinner();\n spinner.start('Copying repository...');\n\n // Copy files from cloned repo to tuck directory\n await copy(repoDir, tuckDir, { overwrite: true });\n\n spinner.stop('Repository imported');\n\n // Get file count and group by category for display\n const fileCount = Object.keys(analysis.manifest.files).length;\n\n // Group files by category\n const grouped: Record<string, string[]> = {};\n for (const [_id, file] of Object.entries(analysis.manifest.files)) {\n if (!grouped[file.category]) grouped[file.category] = [];\n grouped[file.category].push(file.source);\n }\n\n // Display what's available\n console.log();\n prompts.log.success(`Imported ${fileCount} dotfiles to ~/.tuck`);\n console.log();\n\n // Show files by category with icons\n const { DETECTION_CATEGORIES } = await import('../lib/detect.js');\n for (const [category, files] of Object.entries(grouped)) {\n const categoryInfo = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n console.log(\n c.brand(\n ` ${categoryInfo.icon} ${categoryInfo.name}: ${files.length} file${files.length > 1 ? 's' : ''}`\n )\n );\n }\n\n console.log();\n prompts.note(\n 'Your dotfiles are now in ~/.tuck but NOT applied to your system.\\n\\n' +\n 'To apply them to your system, run:\\n' +\n ' tuck apply # Interactive with merge options\\n' +\n ' tuck restore # Simple restore from backup\\n\\n' +\n 'To see what files are available:\\n' +\n ' tuck list',\n 'Next Steps'\n );\n\n // filesApplied is always 0 - user must explicitly apply via tuck apply/restore\n return { success: true, filesInRepo: fileCount, filesApplied: 0, remoteUrl };\n }\n\n if (analysis.type === 'plain-dotfiles') {\n // Scenario B: Plain dotfiles repository - copy contents and initialize tuck\n prompts.log.step('Repository contains dotfiles but no tuck manifest');\n prompts.log.info('Importing repository and setting up tuck...');\n\n // Copy the repository contents to tuck directory first (preserving existing files)\n const copySpinner = prompts.spinner();\n copySpinner.start('Copying repository contents...');\n await copy(repoDir, tuckDir, { overwrite: true });\n copySpinner.stop('Repository contents copied');\n\n // Now initialize git and create tuck config on top of the copied files\n // Note: The .git directory was copied, so we don't need to reinitialize\n await setDefaultBranch(tuckDir, 'main');\n\n const hostname = (await import('os')).hostname();\n await createManifest(tuckDir, hostname);\n await saveConfig(\n {\n ...defaultConfig,\n repository: { ...defaultConfig.repository, path: tuckDir },\n },\n tuckDir\n );\n\n // Create directory structure for categories (if not already present)\n await createDirectoryStructure(tuckDir);\n await createDefaultFiles(tuckDir, hostname);\n\n // Update remote to use the correct URL (may differ from cloned URL)\n try {\n // Remove existing origin if present and add the correct one\n const { removeRemote } = await import('../lib/git.js');\n await removeRemote(tuckDir, 'origin').catch(() => {\n /* ignore if not exists */\n });\n await addRemote(tuckDir, 'origin', remoteUrl);\n } catch {\n // If removing fails, try adding anyway\n await addRemote(tuckDir, 'origin', remoteUrl).catch(() => {\n /* ignore if already exists */\n });\n }\n\n // Detect dotfiles on system that could be tracked\n const detected = analysis.files.filter((f) => !f.sensitive);\n\n console.log();\n prompts.log.success('Repository imported to ~/.tuck');\n prompts.log.info(\"The repository's files are now in your tuck directory.\");\n\n if (detected.length > 0) {\n console.log();\n prompts.log.info(`Found ${detected.length} dotfiles on your system that could be tracked`);\n\n const trackNow = await prompts.confirm('Would you like to add some of these to tuck?', true);\n\n if (trackNow) {\n // Group by category for display\n const grouped: Record<string, DetectedFile[]> = {};\n for (const file of detected) {\n if (!grouped[file.category]) grouped[file.category] = [];\n grouped[file.category].push(file);\n }\n\n // Show categories\n console.log();\n for (const [category, files] of Object.entries(grouped)) {\n const config = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n console.log(` ${config.icon} ${config.name}: ${files.length} files`);\n }\n\n console.log();\n prompts.log.info(\"Run 'tuck scan' to interactively select files to track\");\n prompts.log.info(\"Or run 'tuck add <path>' to add specific files\");\n }\n }\n\n // Count the files that were copied (excluding .git and tuck config files)\n let importedCount = 0;\n const { readdir, stat } = await import('fs/promises');\n try {\n const countFiles = async (dir: string): Promise<number> => {\n let count = 0;\n const entries = await readdir(dir);\n for (const entry of entries) {\n if (entry === '.git' || entry === '.tuckmanifest.json' || entry === '.tuckrc.json')\n continue;\n const fullPath = join(dir, entry);\n const stats = await stat(fullPath).catch(() => null);\n if (stats?.isDirectory()) {\n count += await countFiles(fullPath);\n } else if (stats?.isFile()) {\n count++;\n }\n }\n return count;\n };\n importedCount = await countFiles(tuckDir);\n } catch {\n // Ignore counting errors\n }\n\n // For plain-dotfiles, importedCount represents files copied to ~/.tuck\n // No files are applied to system in this flow (user needs to add them manually)\n return { success: true, filesInRepo: importedCount, filesApplied: 0, remoteUrl };\n }\n\n // Scenario C: Messed up repository\n prompts.log.warning(`Repository issue: ${analysis.reason}`);\n console.log();\n\n const action = await prompts.select('How would you like to proceed?', [\n {\n value: 'fresh',\n label: 'Start fresh',\n hint: 'Initialize tuck and set this repo as remote (will overwrite on push)',\n },\n {\n value: 'remote-only',\n label: 'Set as remote only',\n hint: 'Initialize tuck locally, keep existing repo contents',\n },\n {\n value: 'cancel',\n label: 'Cancel',\n hint: 'Inspect the repository manually first',\n },\n ]);\n\n if (action === 'cancel') {\n return { success: false, filesInRepo: 0, filesApplied: 0 };\n }\n\n // Initialize tuck\n await createDirectoryStructure(tuckDir);\n await initRepo(tuckDir);\n await setDefaultBranch(tuckDir, 'main');\n\n const hostname = (await import('os')).hostname();\n await createManifest(tuckDir, hostname);\n await saveConfig(\n {\n ...defaultConfig,\n repository: { ...defaultConfig.repository, path: tuckDir },\n },\n tuckDir\n );\n await createDefaultFiles(tuckDir, hostname);\n\n // Set up remote\n await addRemote(tuckDir, 'origin', remoteUrl);\n\n if (action === 'fresh') {\n prompts.log.info('Tuck initialized. When you push, it will replace the repository contents.');\n prompts.log.info(\n \"Run 'tuck add' to track files, then 'tuck sync && tuck push --force' to update remote\"\n );\n } else {\n prompts.log.info('Tuck initialized with remote configured');\n prompts.log.info(\"Run 'tuck add' to start tracking files\");\n }\n\n // For messed-up repos, no files are imported or applied\n return { success: true, filesInRepo: 0, filesApplied: 0, remoteUrl };\n};\n\nconst initFromRemote = async (tuckDir: string, remoteUrl: string): Promise<void> => {\n // Clone the repository\n await withSpinner(`Cloning from ${remoteUrl}...`, async () => {\n await cloneRepo(remoteUrl, tuckDir);\n });\n\n // Verify manifest exists\n if (!(await pathExists(getManifestPath(tuckDir)))) {\n logger.warning('No manifest found in cloned repository. Creating new manifest...');\n const hostname = (await import('os')).hostname();\n await createManifest(tuckDir, hostname);\n }\n\n // Verify config exists\n if (!(await pathExists(getConfigPath(tuckDir)))) {\n logger.warning('No config found in cloned repository. Creating default config...');\n await saveConfig(\n {\n ...defaultConfig,\n repository: { ...defaultConfig.repository, path: tuckDir },\n },\n tuckDir\n );\n }\n};\n\nconst runInteractiveInit = async (): Promise<void> => {\n banner();\n prompts.intro('tuck init');\n\n // Ask for tuck directory\n const dirInput = await prompts.text('Where should tuck store your dotfiles?', {\n defaultValue: '~/.tuck',\n });\n const tuckDir = getTuckDir(dirInput);\n\n // Check if already initialized\n if (await pathExists(getManifestPath(tuckDir))) {\n prompts.log.error(`Tuck is already initialized at ${collapsePath(tuckDir)}`);\n prompts.outro('Use `tuck status` to see current state');\n return;\n }\n\n // ========== STEP 0: Provider Selection ==========\n console.log();\n let providerResult: ProviderSetupResult | null = null;\n\n // Run provider selection and setup\n providerResult = await setupProvider();\n\n if (!providerResult) {\n // User cancelled provider selection - use local mode\n providerResult = {\n success: true,\n mode: 'local',\n config: buildRemoteConfig('local'),\n provider: getProvider('local'),\n };\n }\n\n // Display the chosen provider\n console.log();\n prompts.log.info(`Provider: ${describeProviderConfig(providerResult.config)}`);\n\n // Flow control flags\n let skipExistingRepoQuestion = false;\n let remoteUrl: string | null = providerResult.remoteUrl || null;\n let existingRepoToUseAsRemote: string | null = null;\n\n // Auto-detect existing dotfiles repository (only for GitHub/GitLab providers)\n const canSearchForRepos = providerResult.mode === 'github' || providerResult.mode === 'gitlab';\n const ghInstalled = await isGhInstalled();\n const ghAuth =\n canSearchForRepos &&\n providerResult.mode === 'github' &&\n ghInstalled &&\n (await isGhAuthenticated());\n\n if (ghAuth) {\n const spinner = prompts.spinner();\n spinner.start('Checking for existing dotfiles repository on GitHub...');\n\n try {\n const user = await getAuthenticatedUser();\n const existingRepoName = await findDotfilesRepo(user.login);\n\n if (existingRepoName) {\n spinner.stop(`Found repository: ${existingRepoName}`);\n\n const importRepo = await prompts.confirm(`Import dotfiles from ${existingRepoName}?`, true);\n\n if (importRepo) {\n // Clone to temp directory\n const tempDir = join(tmpdir(), `tuck-import-${Date.now()}`);\n const cloneSpinner = prompts.spinner();\n cloneSpinner.start('Cloning repository...');\n let phase: 'cloning' | 'analyzing' | 'importing' = 'cloning';\n\n try {\n await ghCloneRepo(existingRepoName, tempDir);\n cloneSpinner.stop('Repository cloned');\n phase = 'analyzing';\n\n // Analyze the repository\n const analysisSpinner = prompts.spinner();\n analysisSpinner.start('Analyzing repository...');\n let analysis: RepositoryAnalysis;\n try {\n analysis = await analyzeRepository(tempDir);\n analysisSpinner.stop('Analysis complete');\n } catch (error) {\n analysisSpinner.stop('Analysis failed');\n throw new Error(\n `Failed to analyze repository: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n phase = 'importing';\n // Import based on analysis\n const result = await importExistingRepo(tuckDir, existingRepoName, analysis, tempDir);\n\n if (result.success) {\n console.log();\n // Always show that repository was imported to ~/.tuck\n if (result.filesInRepo > 0) {\n prompts.log.success(`Repository imported to ~/.tuck (${result.filesInRepo} files)`);\n if (result.filesApplied > 0) {\n prompts.log.info(`Applied ${result.filesApplied} files to your system`);\n } else if (result.filesInRepo > 0) {\n prompts.log.info(\n 'Files are ready in ~/.tuck. Run \"tuck restore\" to apply them to your system'\n );\n }\n } else {\n prompts.log.success(`Tuck initialized with ${existingRepoName} as remote`);\n }\n\n prompts.outro('Ready to manage your dotfiles!');\n\n nextSteps([\n `View status: tuck status`,\n `Add files: tuck add ~/.zshrc`,\n `Sync: tuck sync`,\n ]);\n return;\n }\n\n // User cancelled - continue with normal flow\n console.log();\n } catch (error) {\n // Only stop clone spinner if we're still in cloning phase\n if (phase === 'cloning') {\n cloneSpinner.stop('Clone failed');\n }\n\n // Provide accurate error messages based on which phase failed\n const errorMessage = error instanceof Error ? error.message : String(error);\n if (phase === 'analyzing') {\n prompts.log.warning(errorMessage);\n } else if (phase === 'importing') {\n prompts.log.warning(errorMessage);\n } else {\n prompts.log.warning(`Could not clone repository: ${errorMessage}`);\n }\n console.log();\n\n // Offer to use the failed repo as remote and continue with fresh init\n const useAsRemoteAnyway = await prompts.confirm(\n `Use ${existingRepoName} as your remote and start fresh?`,\n true\n );\n\n if (useAsRemoteAnyway) {\n existingRepoToUseAsRemote = existingRepoName;\n skipExistingRepoQuestion = true;\n }\n } finally {\n // Always clean up temp directory if it exists\n if (await pathExists(tempDir)) {\n try {\n await rm(tempDir, { recursive: true, force: true });\n } catch (cleanupError) {\n // Log but don't throw - cleanup failure shouldn't break the flow\n prompts.log.warning(\n `Failed to clean up temporary directory: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`\n );\n }\n }\n }\n } else {\n // User declined to import - offer to use as remote only\n console.log();\n const useAsRemote = await prompts.confirm(\n `Use ${existingRepoName} as your remote (without importing its contents)?`,\n true\n );\n\n if (useAsRemote) {\n existingRepoToUseAsRemote = existingRepoName;\n }\n skipExistingRepoQuestion = true;\n }\n } else {\n spinner.stop('No existing dotfiles repository found');\n }\n } catch {\n spinner.stop('Could not check for existing repositories');\n }\n }\n\n // Ask about existing repo (manual flow) - skip if we already handled it\n if (!skipExistingRepoQuestion) {\n const hasExisting = await prompts.select('Do you have an existing dotfiles repository?', [\n { value: 'no', label: 'No, start fresh' },\n { value: 'yes', label: 'Yes, clone from URL' },\n ]);\n\n if (hasExisting === 'yes') {\n const repoUrl = await prompts.text('Enter repository URL:', {\n placeholder: 'git@host:user/dotfiles.git or https://host/user/dotfiles.git',\n validate: validateGitUrl,\n });\n\n await initFromRemote(tuckDir, repoUrl);\n\n prompts.log.success('Repository cloned successfully!');\n\n const shouldRestore = await prompts.confirm('Would you like to restore dotfiles now?', true);\n\n if (shouldRestore) {\n console.log();\n // Dynamically import and run restore\n const { runRestore } = await import('./restore.js');\n await runRestore({ all: true });\n }\n\n prompts.outro('Tuck initialized successfully!');\n nextSteps([\n `View status: tuck status`,\n `Add files: tuck add ~/.zshrc`,\n `Sync: tuck sync`,\n ]);\n return;\n }\n }\n\n // Initialize from scratch with provider config\n await initFromScratch(tuckDir, { remoteConfig: providerResult.config });\n\n // If we have an existing repo to use as remote, set it up now\n if (existingRepoToUseAsRemote) {\n const protocol = await getPreferredRemoteProtocol();\n remoteUrl =\n protocol === 'ssh'\n ? `git@github.com:${existingRepoToUseAsRemote}.git`\n : `https://github.com/${existingRepoToUseAsRemote}.git`;\n\n await addRemote(tuckDir, 'origin', remoteUrl);\n prompts.log.success(`Remote set to ${existingRepoToUseAsRemote}`);\n prompts.log.info('Your next push will update the remote repository');\n console.log();\n }\n\n // ========== STEP 1: Remote Setup (if not already configured and not local mode) ==========\n // Skip remote setup if we already have a URL or if we're in local mode\n if (!remoteUrl && providerResult.mode !== 'local') {\n const wantsRemote = await prompts.confirm(\n 'Would you like to set up a remote repository?',\n true\n );\n\n if (wantsRemote) {\n // Try GitHub auto-setup\n const ghResult = await setupGitHubRepo(tuckDir);\n remoteUrl = ghResult.remoteUrl;\n\n // If GitHub setup didn't add a remote, show manual instructions\n if (!ghResult.remoteUrl) {\n // Get user info for examples\n const user = await getAuthenticatedUser().catch(() => null);\n const suggestedName = 'dotfiles';\n\n console.log();\n prompts.note(\n `To create a GitHub repository manually:\\n\\n` +\n `1. Go to: https://github.com/new\\n` +\n `2. Repository name: ${suggestedName}\\n` +\n `3. Description: My dotfiles managed with tuck\\n` +\n `4. Visibility: Private (recommended)\\n` +\n `5. IMPORTANT: Do NOT initialize with:\\n` +\n ` - NO README\\n` +\n ` - NO .gitignore\\n` +\n ` - NO license\\n` +\n `6. Click \"Create repository\"\\n` +\n `7. Copy the URL shown\\n\\n` +\n `Example URLs:\\n` +\n ` SSH: git@github.com:${user?.login || 'username'}/${suggestedName}.git\\n` +\n ` HTTPS: https://github.com/${user?.login || 'username'}/${suggestedName}.git`,\n 'Manual Repository Setup'\n );\n console.log();\n\n const useManual = await prompts.confirm('Did you create a GitHub repository?', true);\n\n if (useManual) {\n const manualUrl = await prompts.text('Paste your GitHub repository URL:', {\n placeholder: `git@github.com:${user?.login || 'user'}/${suggestedName}.git`,\n validate: validateGitHubUrl,\n });\n\n if (manualUrl) {\n await addRemote(tuckDir, 'origin', manualUrl);\n prompts.log.success('Remote added successfully');\n remoteUrl = manualUrl;\n }\n }\n }\n }\n }\n\n // ========== STEP 2: Detect and Select Files ==========\n const scanSpinner = prompts.spinner();\n scanSpinner.start('Scanning for dotfiles...');\n const detectedFiles = await detectDotfiles();\n const nonSensitiveFiles = detectedFiles.filter((f) => !f.sensitive);\n const sensitiveFiles = detectedFiles.filter((f) => f.sensitive);\n scanSpinner.stop(`Found ${detectedFiles.length} dotfiles on your system`);\n\n let trackedCount = 0;\n\n // Handle non-sensitive files\n if (nonSensitiveFiles.length > 0) {\n // Group by category and show summary\n const grouped: Record<string, DetectedFile[]> = {};\n for (const file of nonSensitiveFiles) {\n if (!grouped[file.category]) grouped[file.category] = [];\n grouped[file.category].push(file);\n }\n\n console.log();\n const categoryOrder = ['shell', 'git', 'editors', 'terminal', 'ssh', 'misc'];\n const sortedCategories = Object.keys(grouped).sort((a, b) => {\n const aIdx = categoryOrder.indexOf(a);\n const bIdx = categoryOrder.indexOf(b);\n if (aIdx === -1 && bIdx === -1) return a.localeCompare(b);\n if (aIdx === -1) return 1;\n if (bIdx === -1) return -1;\n return aIdx - bIdx;\n });\n\n for (const category of sortedCategories) {\n const files = grouped[category];\n const config = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n console.log(` ${config.icon} ${config.name}: ${files.length} files`);\n }\n console.log();\n\n const trackNow = await prompts.confirm('Would you like to track some of these now?', true);\n\n if (trackNow) {\n // Show multiselect with all files PRE-SELECTED by default\n const options = nonSensitiveFiles.map((f) => ({\n value: f.path,\n label: `${collapsePath(f.path)}`,\n hint: f.category,\n }));\n\n // Pre-select all non-sensitive files\n const initialValues = nonSensitiveFiles.map((f) => f.path);\n\n const selectedFiles = await prompts.multiselect(\n 'Select files to track (all pre-selected; use space to toggle selection):',\n options,\n { initialValues }\n );\n\n // Handle sensitive files with individual prompts\n const filesToTrack = [...selectedFiles];\n\n if (sensitiveFiles.length > 0) {\n console.log();\n prompts.log.warning(`Found ${sensitiveFiles.length} sensitive file(s):`);\n\n for (const sf of sensitiveFiles) {\n console.log(c.warning(` ! ${collapsePath(sf.path)} - ${sf.description || sf.category}`));\n }\n\n console.log();\n const trackSensitive = await prompts.confirm(\n 'Would you like to review sensitive files? (Ensure your repo is PRIVATE)',\n false\n );\n\n if (trackSensitive) {\n for (const sf of sensitiveFiles) {\n const track = await prompts.confirm(`Track ${collapsePath(sf.path)}?`, false);\n if (track) {\n filesToTrack.push(sf.path);\n }\n }\n }\n }\n\n if (filesToTrack.length > 0) {\n // Track files with beautiful progress display\n trackedCount = await trackFilesWithProgressInit(filesToTrack, tuckDir);\n }\n } else {\n prompts.log.info(\"Run 'tuck scan' later to interactively add files\");\n }\n }\n\n // Handle case where only sensitive files were found\n if (nonSensitiveFiles.length === 0 && sensitiveFiles.length > 0) {\n console.log();\n prompts.log.warning(`Found ${sensitiveFiles.length} sensitive file(s):`);\n\n for (const sf of sensitiveFiles) {\n console.log(c.warning(` ! ${collapsePath(sf.path)} - ${sf.description || sf.category}`));\n }\n\n console.log();\n const trackSensitive = await prompts.confirm(\n 'Would you like to review these sensitive files? (Ensure your repo is PRIVATE)',\n false\n );\n\n if (trackSensitive) {\n const filesToTrack: string[] = [];\n for (const sf of sensitiveFiles) {\n const track = await prompts.confirm(`Track ${collapsePath(sf.path)}?`, false);\n if (track) {\n filesToTrack.push(sf.path);\n }\n }\n\n if (filesToTrack.length > 0) {\n // Track files with beautiful progress display\n trackedCount = await trackFilesWithProgressInit(filesToTrack, tuckDir);\n }\n } else {\n prompts.log.info(\"Run 'tuck scan' later to interactively add files\");\n }\n }\n\n // Handle case where no files were found\n if (detectedFiles.length === 0) {\n console.log();\n prompts.log.info('No dotfiles detected on your system');\n prompts.log.info(\"Run 'tuck add <path>' to manually track files\");\n }\n\n // ========== STEP 3: Commit and Push ==========\n if (trackedCount > 0) {\n console.log();\n\n if (remoteUrl) {\n // Remote is configured - offer to commit AND push\n const action = await prompts.select('Your files are tracked. What would you like to do?', [\n {\n value: 'commit-push',\n label: 'Commit and push to remote',\n hint: 'Recommended - sync your dotfiles now',\n },\n {\n value: 'commit-only',\n label: 'Commit only',\n hint: \"Save locally, push later with 'tuck push'\",\n },\n {\n value: 'skip',\n label: 'Skip for now',\n hint: \"Run 'tuck sync' later\",\n },\n ]);\n\n if (action !== 'skip') {\n const commitSpinner = prompts.spinner();\n commitSpinner.start('Committing changes...');\n\n await stageAll(tuckDir);\n const commitHash = await commit(tuckDir, `Add ${trackedCount} dotfiles via tuck init`);\n\n commitSpinner.stop(`Committed: ${commitHash.slice(0, 7)}`);\n\n if (action === 'commit-push') {\n const pushSpinner = prompts.spinner();\n pushSpinner.start('Pushing to remote...');\n\n try {\n await push(tuckDir, { remote: 'origin', branch: 'main', setUpstream: true });\n pushSpinner.stop('Pushed successfully!');\n\n // Show success with URL\n let viewUrl = remoteUrl;\n if (viewUrl.startsWith('git@github.com:')) {\n viewUrl = viewUrl\n .replace('git@github.com:', 'https://github.com/')\n .replace('.git', '');\n } else if (viewUrl.startsWith('https://github.com/')) {\n viewUrl = viewUrl.replace('.git', '');\n }\n\n console.log();\n prompts.note(\n `Your dotfiles are now live at:\\n${viewUrl}\\n\\n` +\n `On a new machine, run:\\n tuck init --from ${viewUrl}`,\n 'Success!'\n );\n } catch (error) {\n pushSpinner.stop('Push failed');\n const errorMsg = error instanceof Error ? error.message : String(error);\n prompts.log.warning(`Could not push: ${errorMsg}`);\n prompts.log.info(\"Run 'tuck push' to try again\");\n }\n } else {\n prompts.log.info(\"Run 'tuck push' when you're ready to upload to remote\");\n }\n }\n } else {\n // No remote configured\n const shouldCommit = await prompts.confirm('Commit these changes locally?', true);\n\n if (shouldCommit) {\n const commitSpinner = prompts.spinner();\n commitSpinner.start('Committing...');\n\n await stageAll(tuckDir);\n const commitHash = await commit(tuckDir, `Add ${trackedCount} dotfiles via tuck init`);\n\n commitSpinner.stop(`Committed: ${commitHash.slice(0, 7)}`);\n prompts.log.info(\"Set up a remote with 'tuck push' to backup your dotfiles\");\n }\n }\n }\n\n prompts.outro('Tuck initialized successfully!');\n\n nextSteps([\n `View status: tuck status`,\n `Add files: tuck add ~/.zshrc`,\n `Sync: tuck sync`,\n ]);\n};\n\nconst runInit = async (options: InitOptions): Promise<void> => {\n const tuckDir = getTuckDir(options.dir);\n\n // If --from is provided, clone from remote\n if (options.from) {\n await initFromRemote(tuckDir, options.from);\n logger.success(`Tuck initialized from ${options.from}`);\n logger.info('Run `tuck restore --all` to restore dotfiles');\n return;\n }\n\n // Initialize from scratch\n // If remote URL is provided, detect provider from URL\n const detectedConfig = options.remote\n ? buildRemoteConfig(detectProviderFromUrl(options.remote), { url: options.remote })\n : buildRemoteConfig('local');\n\n await initFromScratch(tuckDir, {\n remote: options.remote,\n bare: options.bare,\n remoteConfig: detectedConfig,\n });\n\n logger.success(`Tuck initialized at ${collapsePath(tuckDir)}`);\n\n nextSteps([\n `Add files: tuck add ~/.zshrc`,\n `Sync changes: tuck sync`,\n `Push remote: tuck push`,\n ]);\n};\n\nexport const initCommand = new Command('init')\n .description('Initialize tuck repository')\n .option('-d, --dir <path>', 'Directory for tuck repository', '~/.tuck')\n .option('-r, --remote <url>', 'Git remote URL to set up')\n .option('--bare', 'Initialize without any default files')\n .option('--from <url>', 'Clone from existing tuck repository')\n .action(async (options: InitOptions) => {\n // If no options provided, run interactive mode\n if (!options.remote && !options.bare && !options.from && options.dir === '~/.tuck') {\n await runInteractiveInit();\n } else {\n await runInit(options);\n }\n });\n","/**\n * Provider Setup Utilities\n *\n * Handles the interactive provider selection and setup flow.\n * Used during `tuck init` and `tuck config remote`.\n */\n\nimport { prompts, colors as c } from '../ui/index.js';\nimport {\n getProviderOptions,\n getProvider,\n buildRemoteConfig,\n type ProviderMode,\n type RemoteConfig,\n type GitProvider,\n type ProviderOption,\n} from './providers/index.js';\nimport { validateHostname } from './validation.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ProviderSetupResult {\n /** Whether setup completed successfully */\n success: boolean;\n /** The selected provider mode */\n mode: ProviderMode;\n /** The remote configuration to save */\n config: RemoteConfig;\n /** The provider instance */\n provider: GitProvider;\n /** Remote URL if configured */\n remoteUrl?: string;\n /** Whether initial push was completed */\n pushed?: boolean;\n}\n\n// ============================================================================\n// Provider Selection UI\n// ============================================================================\n\n/**\n * Display available providers with their status\n */\nfunction displayProviderStatus(options: ProviderOption[]): void {\n console.log();\n console.log(c.brand(' Available Git Providers:'));\n console.log();\n\n for (const opt of options) {\n const status = getProviderStatusIcon(opt);\n const authInfo = opt.authStatus?.username ? c.muted(` (@${opt.authStatus.username})`) : '';\n\n console.log(` ${status} ${opt.displayName}${authInfo}`);\n\n if (opt.unavailableReason) {\n console.log(c.muted(` ${opt.unavailableReason}`));\n }\n }\n\n console.log();\n}\n\n/**\n * Get a status icon for a provider option\n */\nfunction getProviderStatusIcon(opt: ProviderOption): string {\n if (opt.authStatus?.authenticated) {\n return c.success('✓'); // Authenticated\n }\n if (opt.available) {\n return c.warning('○'); // Available but not authenticated\n }\n return c.muted('✗'); // Not available\n}\n\n/**\n * Prompt user to select a git provider\n */\nexport async function selectProvider(): Promise<ProviderMode | null> {\n // Detect available providers\n const spinner = prompts.spinner();\n spinner.start('Detecting available git providers...');\n\n const options = await getProviderOptions();\n\n spinner.stop('Provider detection complete');\n\n // Display provider status\n displayProviderStatus(options);\n\n // Build selection options with explicit type\n type SelectValue = ProviderMode | 'skip';\n\n const selectOptions: Array<{ value: SelectValue; label: string; hint: string }> = options.map(\n (opt) => {\n let hint = opt.description;\n\n if (opt.authStatus?.authenticated && opt.authStatus.username) {\n hint = `Logged in as @${opt.authStatus.username}`;\n } else if (opt.unavailableReason) {\n hint = opt.unavailableReason;\n }\n\n return {\n value: opt.mode as SelectValue,\n label: opt.displayName,\n hint,\n };\n }\n );\n\n // Add \"Skip for now\" option\n selectOptions.push({\n value: 'skip',\n label: 'Skip for now',\n hint: 'Set up remote later with tuck config remote',\n });\n\n const selected = await prompts.select<SelectValue>(\n 'Where would you like to store your dotfiles?',\n selectOptions\n );\n\n if (selected === 'skip') {\n return null;\n }\n\n return selected;\n}\n\n/**\n * Run the full provider setup flow\n */\nexport async function setupProvider(\n initialMode?: ProviderMode\n): Promise<ProviderSetupResult | null> {\n // Select provider if not specified\n const mode = initialMode ?? (await selectProvider());\n\n if (!mode) {\n // User chose to skip\n return {\n success: true,\n mode: 'local',\n config: buildRemoteConfig('local'),\n provider: getProvider('local'),\n };\n }\n\n const provider = getProvider(mode);\n\n // Handle each provider type\n switch (mode) {\n case 'local':\n return await setupLocalProvider();\n\n case 'github':\n return await setupGitHubProvider(provider);\n\n case 'gitlab':\n return await setupGitLabProvider(provider);\n\n case 'custom':\n return await setupCustomProvider(provider);\n\n default:\n prompts.log.error(`Unknown provider: ${mode}`);\n return null;\n }\n}\n\n// ============================================================================\n// Provider-Specific Setup\n// ============================================================================\n\n/**\n * Setup local-only mode (no remote)\n */\nasync function setupLocalProvider(): Promise<ProviderSetupResult> {\n prompts.log.info('Your dotfiles will be tracked locally without remote sync.');\n prompts.log.info(\"You can set up a remote later with 'tuck config remote'.\");\n\n return {\n success: true,\n mode: 'local',\n config: buildRemoteConfig('local'),\n provider: getProvider('local'),\n };\n}\n\n/**\n * Setup GitHub provider\n */\nasync function setupGitHubProvider(provider: GitProvider): Promise<ProviderSetupResult | null> {\n const detection = await provider.detect();\n\n // Check if CLI is installed\n if (!detection.authStatus.cliInstalled) {\n prompts.log.warning('GitHub CLI (gh) is not installed.');\n console.log();\n prompts.note(provider.getSetupInstructions(), 'Installation Instructions');\n console.log();\n\n const altChoice = await prompts.select('How would you like to proceed?', [\n { value: 'install', label: 'I will install gh CLI', hint: 'Run tuck init again after' },\n { value: 'custom', label: 'Use custom URL instead', hint: 'Manual repository setup' },\n { value: 'local', label: 'Stay local for now', hint: 'No remote sync' },\n ]);\n\n if (altChoice === 'local') {\n return setupLocalProvider();\n }\n\n if (altChoice === 'custom') {\n return setupCustomProvider(getProvider('custom'));\n }\n\n // User will install CLI\n prompts.log.info(\"After installing, run 'tuck init' again.\");\n return null;\n }\n\n // Check if authenticated\n if (!detection.authStatus.authenticated) {\n prompts.log.warning('GitHub CLI is installed but not authenticated.');\n\n const authChoice = await prompts.select('Would you like to authenticate now?', [\n { value: 'auth', label: 'Run gh auth login', hint: 'Authenticate via browser' },\n { value: 'custom', label: 'Use custom URL instead', hint: 'Manual repository setup' },\n { value: 'local', label: 'Stay local for now', hint: 'No remote sync' },\n ]);\n\n if (authChoice === 'local') {\n return setupLocalProvider();\n }\n\n if (authChoice === 'custom') {\n return setupCustomProvider(getProvider('custom'));\n }\n\n // Run gh auth login\n prompts.log.info('Opening browser for GitHub authentication...');\n try {\n const { execFile } = await import('child_process');\n const { promisify } = await import('util');\n const execFileAsync = promisify(execFile);\n await execFileAsync('gh', ['auth', 'login', '--web']);\n\n // Re-check authentication\n const recheck = await provider.detect();\n if (!recheck.authStatus.authenticated) {\n prompts.log.warning('Authentication may have failed. Please try again.');\n return null;\n }\n\n prompts.log.success(`Authenticated as @${recheck.authStatus.user?.login}`);\n } catch (error) {\n // Sanitize error message to prevent information disclosure\n prompts.log.error('Authentication failed. Please try again or run `gh auth login` manually.');\n return null;\n }\n }\n\n // Get user info\n const user = await provider.getUser();\n if (!user) {\n prompts.log.error('Could not get GitHub user information.');\n return null;\n }\n\n // Confirm account\n const confirmAccount = await prompts.confirm(`Use GitHub account @${user.login}?`, true);\n\n if (!confirmAccount) {\n prompts.log.info(\"Run 'gh auth logout' then 'gh auth login' to switch accounts.\");\n return null;\n }\n\n return {\n success: true,\n mode: 'github',\n config: buildRemoteConfig('github', { username: user.login }),\n provider,\n };\n}\n\n/**\n * Setup GitLab provider\n */\nasync function setupGitLabProvider(provider: GitProvider): Promise<ProviderSetupResult | null> {\n // Ask about self-hosted first\n const hostType = await prompts.select('Which GitLab instance?', [\n { value: 'cloud', label: 'gitlab.com', hint: 'GitLab cloud service' },\n { value: 'self-hosted', label: 'Self-hosted', hint: 'Custom GitLab server' },\n ]);\n\n let providerUrl: string | undefined;\n\n if (hostType === 'self-hosted') {\n const host = await prompts.text('Enter your GitLab host:', {\n placeholder: 'gitlab.example.com',\n validate: (value) => {\n try {\n validateHostname(value);\n return undefined;\n } catch (error) {\n return error instanceof Error ? error.message : 'Invalid hostname';\n }\n },\n });\n\n providerUrl = `https://${host}`;\n\n // Warn about self-signed certificates\n prompts.log.info(\n 'For self-hosted instances with self-signed certificates, ' +\n 'you may need to configure git to skip SSL verification'\n );\n\n // Create provider for this host\n const { GitLabProvider } = await import('./providers/gitlab.js');\n provider = GitLabProvider.forHost(host);\n }\n\n const detection = await provider.detect();\n\n // Check if CLI is installed\n if (!detection.authStatus.cliInstalled) {\n prompts.log.warning('GitLab CLI (glab) is not installed.');\n console.log();\n prompts.note(provider.getSetupInstructions(), 'Installation Instructions');\n console.log();\n\n const altChoice = await prompts.select('How would you like to proceed?', [\n { value: 'install', label: 'I will install glab CLI', hint: 'Run tuck init again after' },\n { value: 'custom', label: 'Use custom URL instead', hint: 'Manual repository setup' },\n { value: 'local', label: 'Stay local for now', hint: 'No remote sync' },\n ]);\n\n if (altChoice === 'local') {\n return setupLocalProvider();\n }\n\n if (altChoice === 'custom') {\n return setupCustomProvider(getProvider('custom'));\n }\n\n prompts.log.info(\"After installing, run 'tuck init' again.\");\n return null;\n }\n\n // Check if authenticated\n if (!detection.authStatus.authenticated) {\n prompts.log.warning(\n `GitLab CLI is installed but not authenticated${providerUrl ? ` for ${providerUrl}` : ''}.`\n );\n\n const authChoice = await prompts.select('Would you like to authenticate now?', [\n { value: 'auth', label: 'Run glab auth login', hint: 'Authenticate via browser' },\n { value: 'custom', label: 'Use custom URL instead', hint: 'Manual repository setup' },\n { value: 'local', label: 'Stay local for now', hint: 'No remote sync' },\n ]);\n\n if (authChoice === 'local') {\n return setupLocalProvider();\n }\n\n if (authChoice === 'custom') {\n return setupCustomProvider(getProvider('custom'));\n }\n\n // Run glab auth login\n prompts.log.info('Opening browser for GitLab authentication...');\n try {\n const { execFile } = await import('child_process');\n const { promisify } = await import('util');\n const execFileAsync = promisify(execFile);\n\n const args = ['auth', 'login', '--web'];\n if (providerUrl) {\n args.push('-h', providerUrl.replace(/^https?:\\/\\//, ''));\n }\n\n await execFileAsync('glab', args);\n\n // Re-check authentication\n const recheck = await provider.detect();\n if (!recheck.authStatus.authenticated) {\n prompts.log.warning('Authentication may have failed. Please try again.');\n return null;\n }\n\n prompts.log.success(`Authenticated as @${recheck.authStatus.user?.login}`);\n } catch (error) {\n // Sanitize error message to prevent information disclosure\n prompts.log.error('Authentication failed. Please try again or run `glab auth login` manually.');\n return null;\n }\n }\n\n // Get user info\n const user = await provider.getUser();\n if (!user) {\n prompts.log.error('Could not get GitLab user information.');\n return null;\n }\n\n // Confirm account\n const confirmAccount = await prompts.confirm(\n `Use GitLab account @${user.login}${providerUrl ? ` on ${providerUrl}` : ''}?`,\n true\n );\n\n if (!confirmAccount) {\n prompts.log.info(\"Run 'glab auth logout' then 'glab auth login' to switch accounts.\");\n return null;\n }\n\n return {\n success: true,\n mode: 'gitlab',\n config: buildRemoteConfig('gitlab', { username: user.login, providerUrl }),\n provider,\n };\n}\n\n/**\n * Setup custom provider (manual URL)\n */\nasync function setupCustomProvider(provider: GitProvider): Promise<ProviderSetupResult | null> {\n prompts.log.info('You can use any git remote URL.');\n console.log();\n prompts.note(provider.getSetupInstructions(), 'Custom Remote Setup');\n console.log();\n\n const hasRepo = await prompts.confirm('Do you have a repository URL ready?');\n\n if (!hasRepo) {\n prompts.log.info(\"Create a repository first, then run 'tuck config remote' to add it.\");\n return setupLocalProvider();\n }\n\n const url = await prompts.text('Enter the repository URL:', {\n placeholder: 'https://git.example.com/user/dotfiles.git',\n validate: (value) => {\n if (!value) return 'URL is required';\n if (!provider.validateUrl(value)) {\n return 'Invalid git URL format';\n }\n return undefined;\n },\n });\n\n return {\n success: true,\n mode: 'custom',\n config: buildRemoteConfig('custom', { url }),\n provider,\n remoteUrl: url,\n };\n}\n\n// ============================================================================\n// Provider Configuration\n// ============================================================================\n\n/**\n * Validate and suggest provider based on existing remote URL\n */\nexport function detectProviderFromUrl(url: string): ProviderMode {\n if (url.includes('github.com')) {\n return 'github';\n }\n if (url.includes('gitlab.com') || url.includes('gitlab')) {\n return 'gitlab';\n }\n return 'custom';\n}\n\n/**\n * Get user-friendly message for local mode warning\n */\nexport function getLocalModeWarning(operation: string): string {\n return (\n `Cannot ${operation}: tuck is configured for local-only mode.\\n\\n` +\n `Your dotfiles are tracked locally but not synced to a remote.\\n` +\n `To enable remote sync, run: tuck config remote`\n );\n}\n","/**\n * Git Provider Registry\n *\n * Central registry for managing git providers.\n * Handles provider detection, selection, and instantiation.\n */\n\nimport type { GitProvider, ProviderMode, ProviderDetection, RemoteConfig } from './types.js';\nimport { ProviderNotConfiguredError, LocalModeError } from './types.js';\nimport { GitLabProvider, gitlabProvider } from './gitlab.js';\nimport { githubProvider } from './github.js';\nimport { localProvider } from './local.js';\nimport { CustomProvider, customProvider } from './custom.js';\n\n// Re-export types and errors\nexport * from './types.js';\nexport { GitHubProvider, githubProvider } from './github.js';\nexport { GitLabProvider, gitlabProvider } from './gitlab.js';\nexport { LocalProvider, localProvider } from './local.js';\nexport { CustomProvider, customProvider } from './custom.js';\n\n// ============================================================================\n// Provider Registry\n// ============================================================================\n\n/** All available provider modes */\nexport const PROVIDER_MODES: ProviderMode[] = ['github', 'gitlab', 'local', 'custom'];\n\n/** Provider display info for selection UI */\nexport interface ProviderOption {\n mode: ProviderMode;\n displayName: string;\n description: string;\n available: boolean;\n authStatus?: {\n authenticated: boolean;\n username?: string;\n };\n unavailableReason?: string;\n}\n\n/**\n * Get a provider instance by mode\n */\nexport function getProvider(mode: ProviderMode, config?: RemoteConfig): GitProvider {\n switch (mode) {\n case 'github':\n return githubProvider;\n\n case 'gitlab':\n // Support self-hosted GitLab\n if (config?.providerUrl) {\n const host = config.providerUrl.replace(/^https?:\\/\\//, '').replace(/\\/$/, '');\n return GitLabProvider.forHost(host);\n }\n return gitlabProvider;\n\n case 'local':\n return localProvider;\n\n case 'custom':\n if (config?.url) {\n return CustomProvider.withUrl(config.url);\n }\n return customProvider;\n\n default:\n throw new ProviderNotConfiguredError(mode);\n }\n}\n\n/**\n * Detect all available providers and their auth status\n */\nexport async function detectProviders(): Promise<ProviderDetection[]> {\n const detections = await Promise.all([\n githubProvider.detect(),\n gitlabProvider.detect(),\n localProvider.detect(),\n customProvider.detect(),\n ]);\n\n return detections;\n}\n\n/**\n * Get provider options for interactive selection\n * Sorted by recommendation: authenticated providers first, then by preference\n */\nexport async function getProviderOptions(): Promise<ProviderOption[]> {\n const detections = await detectProviders();\n\n // Create a Map for efficient lookups instead of repeated .find() calls\n const detectionMap = new Map<ProviderMode, ProviderDetection>();\n for (const detection of detections) {\n detectionMap.set(detection.mode, detection);\n }\n\n const github = detectionMap.get('github');\n const gitlab = detectionMap.get('gitlab');\n const custom = detectionMap.get('custom');\n\n const options: ProviderOption[] = [\n {\n mode: 'github',\n displayName: 'GitHub',\n description: 'Store dotfiles on GitHub (recommended)',\n available: github?.available ?? false,\n authStatus: {\n authenticated: github?.authStatus.authenticated ?? false,\n username: github?.authStatus.user?.login,\n },\n unavailableReason: github?.unavailableReason,\n },\n {\n mode: 'gitlab',\n displayName: 'GitLab',\n description: 'Store dotfiles on GitLab (supports self-hosted)',\n available: gitlab?.available ?? false,\n authStatus: {\n authenticated: gitlab?.authStatus.authenticated ?? false,\n username: gitlab?.authStatus.user?.login,\n },\n unavailableReason: gitlab?.unavailableReason,\n },\n {\n mode: 'local',\n displayName: 'Local Only',\n description: 'Track dotfiles locally without remote sync',\n available: true,\n },\n {\n mode: 'custom',\n displayName: 'Custom Remote',\n description: 'Use any git remote URL (Bitbucket, Gitea, etc.)',\n available: custom?.available ?? true,\n },\n ];\n\n // Sort: authenticated first, then available, then rest\n return options.sort((a, b) => {\n // Authenticated providers first\n if (a.authStatus?.authenticated && !b.authStatus?.authenticated) return -1;\n if (!a.authStatus?.authenticated && b.authStatus?.authenticated) return 1;\n\n // Then available providers\n if (a.available && !b.available) return -1;\n if (!a.available && b.available) return 1;\n\n return 0;\n });\n}\n\n/**\n * Check if remote operations are available\n * Throws LocalModeError if in local mode\n */\nexport function assertRemoteAvailable(config: RemoteConfig, operation: string): void {\n if (config.mode === 'local') {\n throw new LocalModeError(operation);\n }\n}\n\n/**\n * Get a user-friendly description of the current provider configuration\n */\nexport function describeProviderConfig(config: RemoteConfig): string {\n switch (config.mode) {\n case 'github':\n return config.username ? `GitHub (@${config.username})` : 'GitHub';\n\n case 'gitlab':\n if (config.providerUrl) {\n const host = config.providerUrl.replace(/^https?:\\/\\//, '');\n return config.username ? `GitLab ${host} (@${config.username})` : `GitLab (${host})`;\n }\n return config.username ? `GitLab (@${config.username})` : 'GitLab';\n\n case 'local':\n return 'Local only (no remote sync)';\n\n case 'custom':\n return config.url ? `Custom: ${config.url}` : 'Custom remote';\n\n default:\n return 'Unknown provider';\n }\n}\n\n/**\n * Validate that a provider configuration is complete\n */\nexport function validateProviderConfig(config: RemoteConfig): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (!config.mode) {\n errors.push('Provider mode is not set');\n }\n\n if (config.mode === 'custom' && !config.url) {\n errors.push('Custom provider requires a remote URL');\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Build a RemoteConfig from provider detection and user input\n */\nexport function buildRemoteConfig(\n mode: ProviderMode,\n options?: {\n url?: string;\n providerUrl?: string;\n username?: string;\n repoName?: string;\n }\n): RemoteConfig {\n return {\n mode,\n url: options?.url,\n providerUrl: options?.providerUrl,\n username: options?.username,\n repoName: options?.repoName,\n };\n}\n","/**\n * GitHub Provider Implementation\n *\n * Provides GitHub integration via the `gh` CLI tool.\n */\n\nimport { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport type {\n GitProvider,\n ProviderUser,\n ProviderRepo,\n CreateRepoOptions,\n ProviderDetection,\n} from './types.js';\nimport { ProviderError } from './types.js';\nimport {\n validateRepoName as validateRepoNameUtil,\n validateDescription as validateDescriptionUtil,\n sanitizeErrorMessage,\n} from '../validation.js';\n\nconst execFileAsync = promisify(execFile);\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst COMMON_DOTFILE_REPO_NAMES = ['dotfiles', 'tuck', '.dotfiles', 'dot-files', 'dots'];\n\n// ============================================================================\n// GitHub Provider\n// ============================================================================\n\nexport class GitHubProvider implements GitProvider {\n readonly mode = 'github' as const;\n readonly displayName = 'GitHub';\n readonly cliName = 'gh';\n readonly requiresRemote = true;\n\n // -------------------------------------------------------------------------\n // Detection & Authentication\n // -------------------------------------------------------------------------\n\n async isCliInstalled(): Promise<boolean> {\n try {\n await execFileAsync('gh', ['--version']);\n return true;\n } catch {\n return false;\n }\n }\n\n async isAuthenticated(): Promise<boolean> {\n try {\n const { stdout, stderr } = await execFileAsync('gh', ['auth', 'status']);\n const output = (stderr || stdout || '').trim();\n return output.includes('Logged in');\n } catch (error) {\n if (error instanceof Error && 'stderr' in error) {\n const stderr = (error as { stderr: string }).stderr;\n return stderr.includes('Logged in');\n }\n return false;\n }\n }\n\n async getUser(): Promise<ProviderUser | null> {\n if (!(await this.isCliInstalled()) || !(await this.isAuthenticated())) {\n return null;\n }\n\n try {\n const { stdout } = await execFileAsync('gh', [\n 'api',\n 'user',\n '--jq',\n '.login, .name, .email',\n ]);\n const lines = stdout.trim().split('\\n');\n return {\n login: lines[0] || '',\n name: lines[1] !== 'null' ? lines[1] : null,\n email: lines[2] !== 'null' ? lines[2] : null,\n };\n } catch {\n return null;\n }\n }\n\n async detect(): Promise<ProviderDetection> {\n const cliInstalled = await this.isCliInstalled();\n\n if (!cliInstalled) {\n return {\n mode: this.mode,\n displayName: this.displayName,\n available: false,\n authStatus: {\n cliInstalled: false,\n authenticated: false,\n },\n unavailableReason: 'GitHub CLI (gh) is not installed',\n };\n }\n\n const authenticated = await this.isAuthenticated();\n const user = authenticated ? await this.getUser() : undefined;\n\n return {\n mode: this.mode,\n displayName: this.displayName,\n available: authenticated,\n authStatus: {\n cliInstalled: true,\n authenticated,\n user: user || undefined,\n },\n unavailableReason: !authenticated ? 'Not logged in to GitHub CLI' : undefined,\n };\n }\n\n // -------------------------------------------------------------------------\n // Repository Operations\n // -------------------------------------------------------------------------\n\n async repoExists(repoName: string): Promise<boolean> {\n this.validateRepoName(repoName);\n try {\n await execFileAsync('gh', ['repo', 'view', repoName, '--json', 'name']);\n return true;\n } catch {\n return false;\n }\n }\n\n async createRepo(options: CreateRepoOptions): Promise<ProviderRepo> {\n if (!(await this.isCliInstalled())) {\n throw new ProviderError('GitHub CLI is not installed', 'github', [\n 'Install with: brew install gh (macOS) or see https://cli.github.com/',\n ]);\n }\n\n if (!(await this.isAuthenticated())) {\n throw new ProviderError('Not authenticated with GitHub CLI', 'github', [\n 'Run: gh auth login',\n ]);\n }\n\n const user = await this.getUser();\n if (!user) {\n throw new ProviderError('Could not get GitHub user information', 'github');\n }\n\n // Validate inputs BEFORE checking if repo exists (to fail fast)\n this.validateRepoName(options.name);\n\n // Validate description if provided (improved validation)\n if (options.description) {\n try {\n validateDescriptionUtil(options.description, 350);\n } catch (error) {\n throw new ProviderError(\n error instanceof Error ? error.message : 'Invalid description',\n 'github'\n );\n }\n }\n\n const fullName = `${user.login}/${options.name}`;\n\n if (await this.repoExists(fullName)) {\n throw new ProviderError(`Repository \"${fullName}\" already exists`, 'github', [\n `Use a different name or import the existing repo`,\n ]);\n }\n\n const args: string[] = ['repo', 'create', options.name];\n\n if (options.isPrivate !== false) {\n args.push('--private');\n } else {\n args.push('--public');\n }\n\n if (options.description) {\n args.push('--description', options.description);\n }\n\n args.push('--confirm', '--json', 'name,url,sshUrl');\n\n try {\n const { stdout } = await execFileAsync('gh', args);\n const result = JSON.parse(stdout);\n\n return {\n name: result.name,\n fullName: `${user.login}/${result.name}`,\n url: result.url,\n sshUrl: result.sshUrl,\n httpsUrl: result.url,\n isPrivate: options.isPrivate !== false,\n };\n } catch (error) {\n // Sanitize error message to prevent information disclosure\n const sanitizedMessage = sanitizeErrorMessage(error, 'Failed to create repository');\n throw new ProviderError(sanitizedMessage, 'github', [\n 'Try creating the repository manually at github.com/new',\n ]);\n }\n }\n\n async getRepoInfo(repoName: string): Promise<ProviderRepo | null> {\n this.validateRepoName(repoName);\n try {\n const { stdout } = await execFileAsync('gh', [\n 'repo',\n 'view',\n repoName,\n '--json',\n 'name,url,sshUrl,isPrivate,owner',\n ]);\n const result = JSON.parse(stdout);\n\n return {\n name: result.name,\n fullName: `${result.owner.login}/${result.name}`,\n url: result.url,\n sshUrl: result.sshUrl,\n httpsUrl: result.url,\n isPrivate: result.isPrivate,\n };\n } catch {\n return null;\n }\n }\n\n async cloneRepo(repoName: string, targetDir: string): Promise<void> {\n if (!(await this.isCliInstalled())) {\n throw new ProviderError('GitHub CLI is not installed', 'github');\n }\n\n this.validateRepoName(repoName);\n\n try {\n await execFileAsync('gh', ['repo', 'clone', repoName, targetDir]);\n } catch (error) {\n throw new ProviderError(`Failed to clone repository \"${repoName}\"`, 'github', [\n String(error),\n 'Check that the repository exists and you have access',\n ]);\n }\n }\n\n async findDotfilesRepo(username?: string): Promise<string | null> {\n const user = username || (await this.getUser())?.login;\n if (!user) return null;\n\n for (const name of COMMON_DOTFILE_REPO_NAMES) {\n const repoName = `${user}/${name}`;\n if (await this.repoExists(repoName)) {\n return repoName;\n }\n }\n\n return null;\n }\n\n // -------------------------------------------------------------------------\n // URL Utilities\n // -------------------------------------------------------------------------\n\n async getPreferredRepoUrl(repo: ProviderRepo): Promise<string> {\n const protocol = await this.getPreferredProtocol();\n return protocol === 'ssh' ? repo.sshUrl : repo.httpsUrl;\n }\n\n validateUrl(url: string): boolean {\n return (\n url.startsWith('https://github.com/') ||\n url.startsWith('git@github.com:') ||\n url.startsWith('ssh://git@github.com/')\n );\n }\n\n buildRepoUrl(username: string, repoName: string, protocol: 'ssh' | 'https'): string {\n if (protocol === 'ssh') {\n return `git@github.com:${username}/${repoName}.git`;\n }\n return `https://github.com/${username}/${repoName}.git`;\n }\n\n // -------------------------------------------------------------------------\n // Instructions\n // -------------------------------------------------------------------------\n\n getSetupInstructions(): string {\n const { platform } = process;\n\n let installCmd = '';\n if (platform === 'darwin') {\n installCmd = 'brew install gh';\n } else if (platform === 'linux') {\n installCmd = `# Debian/Ubuntu:\nsudo apt install gh\n\n# Fedora:\nsudo dnf install gh\n\n# Arch Linux:\nsudo pacman -S github-cli`;\n } else if (platform === 'win32') {\n installCmd = `# Using winget:\nwinget install GitHub.cli\n\n# Using scoop:\nscoop install gh`;\n }\n\n return `GitHub CLI (gh) - Recommended for the best experience\n\nInstallation:\n${installCmd}\n\nAfter installing, authenticate:\ngh auth login\n\nBenefits:\n- Automatic repository creation\n- No manual token management\n- Easy authentication refresh\n\nLearn more: https://cli.github.com/`;\n }\n\n getAltAuthInstructions(): string {\n return `Alternative authentication methods for GitHub:\n\n1. SSH Keys (recommended if gh CLI unavailable)\n - Generate: ssh-keygen -t ed25519\n - Add to GitHub: https://github.com/settings/ssh/new\n - Test: ssh -T git@github.com\n\n2. Personal Access Token\n - Create at: https://github.com/settings/tokens\n - Required scope: \"repo\" for private repositories\n - Use as password when pushing\n\nFor detailed instructions, see:\nhttps://docs.github.com/en/authentication`;\n }\n\n // -------------------------------------------------------------------------\n // Private Helpers\n // -------------------------------------------------------------------------\n\n private validateRepoName(repoName: string): void {\n try {\n validateRepoNameUtil(repoName, 'github');\n } catch (error) {\n throw new ProviderError(\n error instanceof Error ? error.message : 'Invalid repository name',\n 'github'\n );\n }\n }\n\n private async getPreferredProtocol(): Promise<'ssh' | 'https'> {\n try {\n const { stdout } = await execFileAsync('gh', ['config', 'get', 'git_protocol']);\n return stdout.trim().toLowerCase() === 'ssh' ? 'ssh' : 'https';\n } catch {\n return 'https';\n }\n }\n}\n\n// Export singleton instance\nexport const githubProvider = new GitHubProvider();\n","/**\n * Local Provider Implementation\n *\n * A no-op provider for local-only git repositories without remote sync.\n * This allows users to track their dotfiles locally without pushing to any remote.\n */\n\nimport type {\n GitProvider,\n ProviderUser,\n ProviderRepo,\n CreateRepoOptions,\n ProviderDetection,\n} from './types.js';\nimport { LocalModeError } from './types.js';\n\n// ============================================================================\n// Local Provider\n// ============================================================================\n\nexport class LocalProvider implements GitProvider {\n readonly mode = 'local' as const;\n readonly displayName = 'Local Only';\n readonly cliName = null;\n readonly requiresRemote = false;\n\n // -------------------------------------------------------------------------\n // Detection & Authentication\n // -------------------------------------------------------------------------\n\n async isCliInstalled(): Promise<boolean> {\n // Local mode doesn't need any CLI\n return true;\n }\n\n async isAuthenticated(): Promise<boolean> {\n // Local mode doesn't need authentication\n return true;\n }\n\n async getUser(): Promise<ProviderUser | null> {\n // Local mode has no user account\n return null;\n }\n\n async detect(): Promise<ProviderDetection> {\n return {\n mode: this.mode,\n displayName: this.displayName,\n available: true,\n authStatus: {\n cliInstalled: true,\n authenticated: true,\n },\n };\n }\n\n // -------------------------------------------------------------------------\n // Repository Operations\n // -------------------------------------------------------------------------\n\n async repoExists(_repoName: string): Promise<boolean> {\n throw new LocalModeError('check if remote repository exists');\n }\n\n async createRepo(_options: CreateRepoOptions): Promise<ProviderRepo> {\n throw new LocalModeError('create remote repository');\n }\n\n async getRepoInfo(_repoName: string): Promise<ProviderRepo | null> {\n throw new LocalModeError('get remote repository info');\n }\n\n async cloneRepo(_repoName: string, _targetDir: string): Promise<void> {\n throw new LocalModeError('clone remote repository');\n }\n\n async findDotfilesRepo(_username?: string): Promise<string | null> {\n // In local mode, there's no remote to search\n return null;\n }\n\n // -------------------------------------------------------------------------\n // URL Utilities\n // -------------------------------------------------------------------------\n\n async getPreferredRepoUrl(_repo: ProviderRepo): Promise<string> {\n throw new LocalModeError('get remote repository URL');\n }\n\n validateUrl(_url: string): boolean {\n // Local mode doesn't validate remote URLs\n return false;\n }\n\n buildRepoUrl(_username: string, _repoName: string, _protocol: 'ssh' | 'https'): string {\n throw new LocalModeError('build remote repository URL');\n }\n\n // -------------------------------------------------------------------------\n // Instructions\n // -------------------------------------------------------------------------\n\n getSetupInstructions(): string {\n return `Local Only Mode\n\nYour dotfiles are stored in a local git repository without remote sync.\nThis is useful for:\n- Testing tuck before setting up a remote\n- Machines that don't need cloud backup\n- Air-gapped or offline environments\n\nYour dotfiles are still version controlled with git, so you can:\n- Track changes over time\n- Restore previous versions\n- Manually push to a remote later\n\nTo enable remote sync later, run:\n tuck config remote\n\nThis will guide you through setting up GitHub, GitLab, or another provider.`;\n }\n\n getAltAuthInstructions(): string {\n return `To sync your dotfiles to a remote, you'll need to configure a provider.\n\nRun: tuck config remote\n\nAvailable options:\n- GitHub (recommended) - via gh CLI\n- GitLab - via glab CLI \n- Custom - any git remote URL`;\n }\n}\n\n// Export singleton instance\nexport const localProvider = new LocalProvider();\n","/**\n * Custom Provider Implementation\n *\n * Provides support for any git remote via manual URL entry.\n * This is a fallback for providers without CLI tools.\n */\n\nimport { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport type {\n GitProvider,\n ProviderUser,\n ProviderRepo,\n CreateRepoOptions,\n ProviderDetection,\n} from './types.js';\nimport { ProviderError } from './types.js';\nimport {\n validateGitUrl as validateGitUrlUtil,\n GIT_OPERATION_TIMEOUTS,\n sanitizeErrorMessage,\n} from '../validation.js';\n\nconst execFileAsync = promisify(execFile);\n\n// ============================================================================\n// Custom Provider\n// ============================================================================\n\nexport class CustomProvider implements GitProvider {\n readonly mode = 'custom' as const;\n readonly displayName = 'Custom Git Remote';\n readonly cliName = null;\n readonly requiresRemote = true;\n\n /** The custom remote URL */\n private remoteUrl?: string;\n\n constructor(remoteUrl?: string) {\n this.remoteUrl = remoteUrl;\n }\n\n /** Create a provider with a specific URL */\n static withUrl(url: string): CustomProvider {\n const provider = new CustomProvider(url);\n return provider;\n }\n\n /** Set the remote URL */\n setRemoteUrl(url: string): void {\n this.remoteUrl = url;\n }\n\n /** Get the configured remote URL */\n getRemoteUrl(): string | undefined {\n return this.remoteUrl;\n }\n\n // -------------------------------------------------------------------------\n // Detection & Authentication\n // -------------------------------------------------------------------------\n\n async isCliInstalled(): Promise<boolean> {\n // Custom mode uses standard git, which we assume is installed\n try {\n await execFileAsync('git', ['--version']);\n return true;\n } catch {\n return false;\n }\n }\n\n async isAuthenticated(): Promise<boolean> {\n // We can't really check authentication for arbitrary remotes\n // Return true and let push/pull fail if auth is needed\n return true;\n }\n\n async getUser(): Promise<ProviderUser | null> {\n // Try to get user from git config\n try {\n const { stdout: name } = await execFileAsync('git', ['config', '--global', 'user.name']);\n const { stdout: email } = await execFileAsync('git', ['config', '--global', 'user.email']);\n\n const userName = name.trim();\n const userEmail = email.trim();\n\n if (userName || userEmail) {\n return {\n login: userName || userEmail.split('@')[0] || 'user',\n name: userName || null,\n email: userEmail || null,\n };\n }\n } catch {\n // Ignore errors\n }\n return null;\n }\n\n async detect(): Promise<ProviderDetection> {\n const gitInstalled = await this.isCliInstalled();\n\n return {\n mode: this.mode,\n displayName: this.displayName,\n available: gitInstalled,\n authStatus: {\n cliInstalled: gitInstalled,\n authenticated: true, // Assume authenticated for custom\n },\n unavailableReason: !gitInstalled ? 'Git is not installed' : undefined,\n };\n }\n\n // -------------------------------------------------------------------------\n // Repository Operations\n // -------------------------------------------------------------------------\n\n async repoExists(repoUrl: string): Promise<boolean> {\n // Try to list remote refs to check if repo exists and is accessible\n try {\n await execFileAsync('git', ['ls-remote', repoUrl], {\n timeout: GIT_OPERATION_TIMEOUTS.LS_REMOTE,\n });\n return true;\n } catch {\n return false;\n }\n }\n\n async createRepo(_options: CreateRepoOptions): Promise<ProviderRepo> {\n throw new ProviderError('Cannot create repositories with custom provider', 'custom', [\n 'Create your repository manually on your git hosting service',\n 'Then use: tuck init --remote <your-repo-url>',\n ]);\n }\n\n async getRepoInfo(repoUrl: string): Promise<ProviderRepo | null> {\n // Extract name from URL\n const name = this.extractRepoName(repoUrl);\n\n // Check if accessible\n const exists = await this.repoExists(repoUrl);\n if (!exists) {\n return null;\n }\n\n return {\n name,\n fullName: name,\n url: repoUrl,\n sshUrl: repoUrl.startsWith('git@') ? repoUrl : '',\n httpsUrl: repoUrl.startsWith('http') ? repoUrl : '',\n isPrivate: true, // Assume private, we can't know\n };\n }\n\n async cloneRepo(repoUrl: string, targetDir: string): Promise<void> {\n try {\n await execFileAsync('git', ['clone', repoUrl, targetDir], {\n timeout: GIT_OPERATION_TIMEOUTS.CLONE,\n maxBuffer: 10 * 1024 * 1024, // 10MB output limit\n });\n } catch (error) {\n // Check if operation timed out\n if (error && typeof error === 'object' && 'killed' in error && error.killed) {\n throw new ProviderError('Clone operation timed out', 'custom', [\n 'The repository may be too large or the connection is too slow',\n 'Try using git clone directly for large repositories',\n ]);\n }\n\n // Sanitize error message\n const sanitizedMessage = sanitizeErrorMessage(error, 'Failed to clone repository');\n throw new ProviderError(sanitizedMessage, 'custom', [\n 'Check that the URL is correct and you have access',\n 'You may need to set up SSH keys or credentials',\n ]);\n }\n }\n\n async findDotfilesRepo(_username?: string): Promise<string | null> {\n // Can't search for repos with custom provider\n return null;\n }\n\n // -------------------------------------------------------------------------\n // URL Utilities\n // -------------------------------------------------------------------------\n\n async getPreferredRepoUrl(repo: ProviderRepo): Promise<string> {\n // Return SSH URL if available, otherwise HTTPS\n return repo.sshUrl || repo.httpsUrl || repo.url;\n }\n\n validateUrl(url: string): boolean {\n // Use centralized validation with security checks\n return validateGitUrlUtil(url);\n }\n\n buildRepoUrl(_username: string, _repoName: string, _protocol: 'ssh' | 'https'): string {\n // Can't build URLs for unknown providers\n throw new ProviderError('Cannot build repository URLs for custom provider', 'custom', [\n 'Please provide the full repository URL',\n ]);\n }\n\n // -------------------------------------------------------------------------\n // Instructions\n // -------------------------------------------------------------------------\n\n getSetupInstructions(): string {\n return `Custom Git Remote\n\nUse any git hosting service by providing the repository URL directly.\n\nSupported URL formats:\n- HTTPS: https://git.example.com/user/repo.git\n- SSH: git@git.example.com:user/repo.git\n\nSteps:\n1. Create a repository on your git hosting service\n2. Copy the clone URL (SSH or HTTPS)\n3. Run: tuck init --remote <your-repo-url>\n\nNote: You'll need to handle authentication separately:\n- For SSH: Set up SSH keys with your hosting service\n- For HTTPS: Configure git credentials or use a credential helper`;\n }\n\n getAltAuthInstructions(): string {\n return `Authentication for Custom Git Remotes\n\nFor SSH URLs (git@...):\n1. Generate an SSH key: ssh-keygen -t ed25519\n2. Add the public key to your git hosting service\n3. Test: ssh -T git@your-host.com\n\nFor HTTPS URLs:\n1. Create a personal access token on your hosting service\n2. Configure git credential helper:\n git config --global credential.helper store\n3. On first push, enter your token as password\n\nOr use git credential manager for more secure storage.`;\n }\n\n // -------------------------------------------------------------------------\n // Private Helpers\n // -------------------------------------------------------------------------\n\n private extractRepoName(url: string): string {\n // Remove .git suffix\n let name = url.replace(/\\.git$/, '');\n\n // Handle SSH format (git@host:user/repo)\n if (name.includes(':') && !name.includes('://')) {\n name = name.split(':').pop() || name;\n }\n\n // Handle URL format (remove protocol and host)\n if (name.includes('://')) {\n const urlParts = name.split('/');\n name = urlParts.slice(3).join('/'); // Remove protocol + host\n }\n\n // Get just the repo name (last part)\n const parts = name.split('/');\n return parts[parts.length - 1] || 'repository';\n }\n}\n\n// Export singleton instance\nexport const customProvider = new CustomProvider();\n","import { Command } from 'commander';\nimport { basename } from 'path';\nimport { prompts, logger, colors as c } from '../ui/index.js';\nimport {\n getTuckDir,\n expandPath,\n collapsePath,\n pathExists,\n isDirectory,\n detectCategory,\n sanitizeFilename,\n getDestinationPath,\n} from '../lib/paths.js';\nimport { isFileTracked, loadManifest } from '../lib/manifest.js';\nimport { trackFilesWithProgress, type FileToTrack } from '../lib/fileTracking.js';\nimport {\n NotInitializedError,\n FileNotFoundError,\n FileAlreadyTrackedError,\n SecretsDetectedError,\n} from '../errors.js';\nimport { CATEGORIES } from '../constants.js';\nimport type { AddOptions } from '../types.js';\nimport { getDirectoryFileCount, checkFileSizeThreshold, formatFileSize } from '../lib/files.js';\nimport { shouldExcludeFromBin } from '../lib/binary.js';\nimport { addToTuckignore, isIgnored } from '../lib/tuckignore.js';\nimport { loadConfig } from '../lib/config.js';\nimport {\n scanForSecrets,\n processSecretsForRedaction,\n redactFile,\n getSecretsPath,\n type ScanSummary,\n} from '../lib/secrets/index.js';\n\n// SSH private key patterns - NEVER allow these\nconst PRIVATE_KEY_PATTERNS = [\n /^id_rsa$/,\n /^id_dsa$/,\n /^id_ecdsa$/,\n /^id_ed25519$/,\n /^id_.*$/, // Any id_ file without .pub\n /\\.pem$/,\n /\\.key$/,\n /^.*_key$/, // aws_key, github_key, etc.\n];\n\n// Files that should trigger a warning\nconst SENSITIVE_FILE_PATTERNS = [\n /^\\.netrc$/,\n /^\\.aws\\/credentials$/,\n /^\\.docker\\/config\\.json$/,\n /^\\.npmrc$/, // May contain tokens\n /^\\.pypirc$/,\n /^\\.kube\\/config$/,\n /^\\.ssh\\/config$/,\n /^\\.gnupg\\//,\n /credentials/i,\n /secrets?/i,\n /tokens?\\.json$/i,\n /\\.env$/,\n /\\.env\\./,\n];\n\n/**\n * Check if a path is a private key (should never be tracked)\n */\nconst isPrivateKey = (path: string): boolean => {\n const name = basename(path);\n\n // SSH private keys (without .pub extension)\n if (path.includes('.ssh/') && !name.endsWith('.pub')) {\n for (const pattern of PRIVATE_KEY_PATTERNS) {\n if (pattern.test(name)) {\n return true;\n }\n }\n }\n\n // Other private key patterns\n if (name.endsWith('.pem') || name.endsWith('.key')) {\n return true;\n }\n\n return false;\n};\n\n/**\n * Check if a path contains potentially sensitive data\n */\nconst isSensitiveFile = (path: string): boolean => {\n // Strip ~/ prefix if present, since patterns with ^ anchor expect paths without it\n // e.g., ~/.netrc should match /^\\.netrc$/ pattern\n const pathToTest = path.startsWith('~/') ? path.slice(2) : path;\n\n for (const pattern of SENSITIVE_FILE_PATTERNS) {\n if (pattern.test(pathToTest)) {\n return true;\n }\n }\n return false;\n};\n\ninterface FileToAdd {\n source: string;\n destination: string;\n category: string;\n filename: string;\n isDir: boolean;\n fileCount: number;\n sensitive: boolean;\n}\n\nconst validateAndPrepareFiles = async (\n paths: string[],\n tuckDir: string,\n options: AddOptions\n): Promise<FileToAdd[]> => {\n const filesToAdd: FileToAdd[] = [];\n\n for (const path of paths) {\n const expandedPath = expandPath(path);\n const collapsedPath = collapsePath(expandedPath);\n\n // SECURITY: Block private keys\n if (isPrivateKey(collapsedPath)) {\n throw new Error(\n `Cannot track private key: ${path}\\n` +\n `Private keys should NEVER be committed to a repository.\\n` +\n `If you need to backup SSH keys, use a secure password manager.`\n );\n }\n\n // Check if file exists\n if (!(await pathExists(expandedPath))) {\n throw new FileNotFoundError(path);\n }\n\n // Check if already tracked\n if (await isFileTracked(tuckDir, collapsedPath)) {\n throw new FileAlreadyTrackedError(path);\n }\n\n // Check if in .tuckignore\n if (await isIgnored(tuckDir, collapsedPath)) {\n logger.info(`Skipping ${path} (in .tuckignore)`);\n continue;\n }\n\n // Check if binary executable in bin directory\n if (await shouldExcludeFromBin(expandedPath)) {\n const sizeCheck = await checkFileSizeThreshold(expandedPath);\n logger.info(\n `Skipping binary executable: ${path}${sizeCheck.size > 0 ? ` (${formatFileSize(sizeCheck.size)})` : ''}` +\n ` - Add to .tuckignore to customize`\n );\n continue;\n }\n\n // Check file size\n const sizeCheck = await checkFileSizeThreshold(expandedPath);\n\n if (sizeCheck.block) {\n // >= 100MB: Block and offer to ignore\n logger.warning(\n `File ${path} is ${formatFileSize(sizeCheck.size)} (exceeds GitHub's 100MB limit)`\n );\n\n const action = await prompts.select('How would you like to proceed?', [\n { value: 'ignore', label: 'Add to .tuckignore and skip' },\n { value: 'cancel', label: 'Cancel operation' },\n ]);\n\n if (action === 'ignore') {\n await addToTuckignore(tuckDir, collapsedPath);\n logger.success(`Added ${path} to .tuckignore`);\n continue; // Skip this file\n } else {\n throw new Error('Operation cancelled');\n }\n }\n\n if (sizeCheck.warn) {\n // 50-100MB: Warn and confirm\n logger.warning(\n `File ${path} is ${formatFileSize(sizeCheck.size)}. ` +\n `GitHub recommends files under 50MB.`\n );\n\n const action = await prompts.select('How would you like to proceed?', [\n { value: 'continue', label: 'Track it anyway' },\n { value: 'ignore', label: 'Add to .tuckignore and skip' },\n { value: 'cancel', label: 'Cancel operation' },\n ]);\n\n if (action === 'ignore') {\n await addToTuckignore(tuckDir, collapsedPath);\n logger.success(`Added ${path} to .tuckignore`);\n continue;\n } else if (action === 'cancel') {\n throw new Error('Operation cancelled');\n }\n // 'continue' falls through to track the file\n }\n\n // Determine if it's a directory\n const isDir = await isDirectory(expandedPath);\n const fileCount = isDir ? await getDirectoryFileCount(expandedPath) : 1;\n\n // Determine category\n const category = options.category || detectCategory(expandedPath);\n\n // Generate filename for storage\n const filename = options.name || sanitizeFilename(expandedPath);\n\n // Determine destination path\n const destination = getDestinationPath(tuckDir, category, filename);\n\n // Check if sensitive\n const sensitive = isSensitiveFile(collapsedPath);\n\n filesToAdd.push({\n source: collapsedPath,\n destination,\n category,\n filename,\n isDir,\n fileCount,\n sensitive,\n });\n }\n\n return filesToAdd;\n};\n\nconst addFiles = async (\n filesToAdd: FileToAdd[],\n tuckDir: string,\n options: AddOptions\n): Promise<void> => {\n // Convert FileToAdd to FileToTrack\n const filesToTrack: FileToTrack[] = filesToAdd.map((f) => ({\n path: f.source,\n category: f.category,\n }));\n\n // Use the shared tracking utility\n await trackFilesWithProgress(filesToTrack, tuckDir, {\n showCategory: true,\n strategy: options.symlink ? 'symlink' : undefined,\n actionVerb: 'Tracking',\n });\n};\n\n// ============================================================================\n// Secret Scanning Integration\n// ============================================================================\n\n/**\n * Display scan results in a formatted way\n */\nconst displaySecretWarning = (summary: ScanSummary): void => {\n console.log();\n console.log(\n c.error(c.bold(` Security Warning: Found ${summary.totalSecrets} potential secret(s)`))\n );\n console.log();\n\n for (const result of summary.results) {\n console.log(` ${c.brand(result.collapsedPath)}`);\n\n for (const match of result.matches) {\n const severityColor =\n match.severity === 'critical'\n ? c.error\n : match.severity === 'high'\n ? c.warning\n : match.severity === 'medium'\n ? c.info\n : c.muted;\n\n console.log(\n ` ${c.muted(`Line ${match.line}:`)} ${match.redactedValue} ${severityColor(`[${match.severity}]`)}`\n );\n }\n console.log();\n }\n};\n\n/**\n * Handle secret detection with interactive user prompt\n * Returns true if operation should continue, false if aborted\n */\nconst handleSecretsDetected = async (\n summary: ScanSummary,\n filesToAdd: FileToAdd[],\n tuckDir: string\n): Promise<{ continue: boolean; filesToAdd: FileToAdd[] }> => {\n displaySecretWarning(summary);\n\n const action = await prompts.select('How would you like to proceed?', [\n {\n value: 'abort',\n label: 'Abort operation',\n hint: 'Do not track these files',\n },\n {\n value: 'redact',\n label: 'Replace with placeholders',\n hint: 'Store originals in secrets.local.json (never committed)',\n },\n {\n value: 'ignore',\n label: 'Add files to .tuckignore',\n hint: 'Skip these files permanently',\n },\n {\n value: 'proceed',\n label: 'Proceed anyway',\n hint: 'Track files with secrets (dangerous!)',\n },\n ]);\n\n switch (action) {\n case 'abort':\n logger.info('Operation aborted');\n return { continue: false, filesToAdd: [] };\n\n case 'redact': {\n // Process secrets for redaction\n const redactionMaps = await processSecretsForRedaction(summary.results, tuckDir);\n\n // Redact each file\n let totalRedacted = 0;\n for (const result of summary.results) {\n const placeholderMap = redactionMaps.get(result.path);\n if (placeholderMap && placeholderMap.size > 0) {\n const redactionResult = await redactFile(result.path, result.matches, placeholderMap);\n totalRedacted += redactionResult.replacements.length;\n }\n }\n\n console.log();\n logger.success(`Replaced ${totalRedacted} secret(s) with placeholders`);\n logger.dim(`Secrets stored in: ${collapsePath(getSecretsPath(tuckDir))} (never committed)`);\n logger.dim(\"Run 'tuck secrets list' to see stored secrets\");\n console.log();\n\n return { continue: true, filesToAdd };\n }\n\n case 'ignore': {\n // Add files with secrets to .tuckignore\n const filesWithSecrets = new Set(summary.results.map((r) => r.collapsedPath));\n\n for (const file of filesToAdd) {\n // Normalize both paths for comparison using collapsePath\n const normalizedFileSource = collapsePath(file.source);\n if (filesWithSecrets.has(normalizedFileSource)) {\n await addToTuckignore(tuckDir, file.source);\n logger.success(`Added ${normalizedFileSource} to .tuckignore`);\n }\n }\n\n // Remove files with secrets from the list\n const remainingFiles = filesToAdd.filter((f) => {\n const normalizedSource = collapsePath(f.source);\n return !filesWithSecrets.has(normalizedSource);\n });\n\n if (remainingFiles.length === 0) {\n logger.info('No files remaining to track');\n return { continue: false, filesToAdd: [] };\n }\n\n return { continue: true, filesToAdd: remainingFiles };\n }\n\n case 'proceed': {\n // Double-confirm for dangerous action\n const confirmed = await prompts.confirm(\n c.error('Are you SURE you want to track files containing secrets?'),\n false\n );\n\n if (!confirmed) {\n logger.info('Operation aborted');\n return { continue: false, filesToAdd: [] };\n }\n\n logger.warning('Proceeding with secrets - be careful not to push to a public repository!');\n return { continue: true, filesToAdd };\n }\n\n default:\n return { continue: false, filesToAdd: [] };\n }\n};\n\n/**\n * Scan files for secrets and handle results\n * Returns updated filesToAdd list (may be modified by user choices)\n */\nconst scanAndHandleSecrets = async (\n filesToAdd: FileToAdd[],\n tuckDir: string,\n options: AddOptions\n): Promise<{ continue: boolean; filesToAdd: FileToAdd[] }> => {\n // Check if scanning is enabled\n const config = await loadConfig(tuckDir);\n const security = config.security || {};\n\n // Skip scanning if disabled or --force is used\n if (security.scanSecrets === false || options.force) {\n return { continue: true, filesToAdd };\n }\n\n // Get file paths for scanning\n const filePaths = filesToAdd.map((f) => expandPath(f.source));\n\n // Scan files\n const summary = await scanForSecrets(filePaths, tuckDir);\n\n // If no secrets found, continue normally\n if (summary.filesWithSecrets === 0) {\n return { continue: true, filesToAdd };\n }\n\n // Handle detected secrets\n return handleSecretsDetected(summary, filesToAdd, tuckDir);\n};\n\nconst runInteractiveAdd = async (tuckDir: string): Promise<void> => {\n prompts.intro('tuck add');\n\n // Ask for paths\n const pathsInput = await prompts.text('Enter file paths to track (space-separated):', {\n placeholder: '~/.zshrc ~/.gitconfig',\n validate: (value) => {\n if (!value.trim()) return 'At least one path is required';\n return undefined;\n },\n });\n\n const paths = pathsInput.split(/\\s+/).filter(Boolean);\n\n // Validate and prepare\n let filesToAdd: FileToAdd[];\n try {\n filesToAdd = await validateAndPrepareFiles(paths, tuckDir, {});\n } catch (error) {\n if (error instanceof Error) {\n prompts.log.error(error.message);\n }\n prompts.cancel();\n return;\n }\n\n // Show what will be added and ask for category confirmation\n for (const file of filesToAdd) {\n prompts.log.step(`${file.source}`);\n\n const categoryOptions = Object.entries(CATEGORIES).map(([name, config]) => ({\n value: name,\n label: `${config.icon} ${name}`,\n hint: file.category === name ? '(auto-detected)' : undefined,\n }));\n\n // Move detected category to top\n categoryOptions.sort((a, b) => {\n if (a.value === file.category) return -1;\n if (b.value === file.category) return 1;\n return 0;\n });\n\n const selectedCategory = await prompts.select('Category:', categoryOptions);\n file.category = selectedCategory as string;\n\n // Update destination with new category\n file.destination = getDestinationPath(tuckDir, file.category, file.filename);\n }\n\n // Confirm\n const confirm = await prompts.confirm(\n `Add ${filesToAdd.length} ${filesToAdd.length === 1 ? 'file' : 'files'}?`,\n true\n );\n\n if (!confirm) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n // Add files\n await addFiles(filesToAdd, tuckDir, {});\n\n prompts.outro(`Added ${filesToAdd.length} ${filesToAdd.length === 1 ? 'file' : 'files'}`);\n logger.info(\"Run 'tuck sync' to commit changes\");\n};\n\n/**\n * Add files programmatically (used by scan command)\n * Note: Throws SecretsDetectedError if secrets are found (unless --force is used)\n * Callers should catch this error and handle it appropriately\n */\nexport const addFilesFromPaths = async (\n paths: string[],\n options: AddOptions = {}\n): Promise<number> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Validate and prepare files\n const filesToAdd = await validateAndPrepareFiles(paths, tuckDir, options);\n\n if (filesToAdd.length === 0) {\n return 0;\n }\n\n // Scan for secrets (unless --force is used)\n if (!options.force) {\n const config = await loadConfig(tuckDir);\n const security = config.security || {};\n\n if (security.scanSecrets !== false) {\n const filePaths = filesToAdd.map((f) => expandPath(f.source));\n const summary = await scanForSecrets(filePaths, tuckDir);\n\n if (summary.filesWithSecrets > 0) {\n // Throw error to prevent silently adding files with secrets\n const filesWithSecrets = summary.results\n .filter((r) => r.hasSecrets)\n .map((r) => collapsePath(r.path));\n throw new SecretsDetectedError(summary.totalSecrets, filesWithSecrets);\n }\n }\n }\n\n // Add files\n await addFiles(filesToAdd, tuckDir, options);\n\n return filesToAdd.length;\n};\n\nconst runAdd = async (paths: string[], options: AddOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n if (paths.length === 0) {\n await runInteractiveAdd(tuckDir);\n return;\n }\n\n // Validate and prepare files\n let filesToAdd = await validateAndPrepareFiles(paths, tuckDir, options);\n\n if (filesToAdd.length === 0) {\n logger.info('No files to add');\n return;\n }\n\n // Scan for secrets (unless --force is used)\n const secretScanResult = await scanAndHandleSecrets(filesToAdd, tuckDir, options);\n if (!secretScanResult.continue) {\n return;\n }\n filesToAdd = secretScanResult.filesToAdd;\n\n if (filesToAdd.length === 0) {\n return;\n }\n\n // Add files\n await addFiles(filesToAdd, tuckDir, options);\n\n // Ask if user wants to sync now\n console.log();\n const shouldSync = await prompts.confirm('Would you like to sync these changes now?', true);\n\n if (shouldSync) {\n console.log();\n // Dynamically import sync to avoid circular dependencies\n const { runSync } = await import('./sync.js');\n await runSync({});\n } else {\n console.log();\n logger.info(\"Run 'tuck sync' when you're ready to commit changes\");\n }\n};\n\nexport const addCommand = new Command('add')\n .description('Track new dotfiles')\n .argument('[paths...]', 'Paths to dotfiles to track')\n .option('-c, --category <name>', 'Category to organize under')\n .option('-n, --name <name>', 'Custom name for the file in manifest')\n .option('--symlink', 'Create symlink instead of copy')\n .option('-f, --force', 'Skip secret scanning (not recommended)')\n // TODO: Encryption and templating are planned for a future version\n // .option('--encrypt', 'Encrypt this file (requires GPG setup)')\n // .option('--template', 'Treat as template with variable substitution')\n .action(async (paths: string[], options: AddOptions) => {\n await runAdd(paths, options);\n });\n","import { open, stat } from 'fs/promises';\nimport { expandPath } from './paths.js';\nimport { basename, dirname } from 'path';\n\n/**\n * Magic numbers for binary executable detection\n */\nconst MAGIC_NUMBERS = {\n // ELF (Linux)\n ELF: Buffer.from([0x7f, 0x45, 0x4c, 0x46]),\n // Mach-O (macOS) - 32-bit\n MACHO_32: Buffer.from([0xfe, 0xed, 0xfa, 0xce]),\n // Mach-O (macOS) - 64-bit\n MACHO_64: Buffer.from([0xcf, 0xfa, 0xed, 0xfe]),\n // Mach-O (macOS) - Universal binary\n MACHO_UNIVERSAL: Buffer.from([0xca, 0xfe, 0xba, 0xbe]),\n // PE (Windows)\n PE: Buffer.from([0x4d, 0x5a]), // \"MZ\"\n};\n\n/**\n * Script file extensions\n */\nconst SCRIPT_EXTENSIONS = [\n '.sh',\n '.bash',\n '.zsh',\n '.fish',\n '.py',\n '.rb',\n '.pl',\n '.js',\n '.ts',\n '.lua',\n '.php',\n '.tcl',\n '.awk',\n '.sed',\n];\n\n/**\n * Check if a buffer starts with a magic number\n */\nconst bufferStartsWith = (buffer: Buffer, magic: Buffer): boolean => {\n if (buffer.length < magic.length) {\n return false;\n }\n for (let i = 0; i < magic.length; i++) {\n if (buffer[i] !== magic[i]) {\n return false;\n }\n }\n return true;\n};\n\n/**\n * Check if file is an executable binary by reading magic numbers\n */\nexport const isBinaryExecutable = async (path: string): Promise<boolean> => {\n const expandedPath = expandPath(path);\n\n try {\n // Check if file exists and get stats\n const stats = await stat(expandedPath);\n\n // Directories are not binaries\n if (stats.isDirectory()) {\n return false;\n }\n\n // Check execute permissions (Unix-like systems)\n // 0o111 = execute bit for owner, group, and others\n const hasExecutePermission = (stats.mode & 0o111) !== 0;\n\n // Read first 512 bytes to check magic numbers\n let fileHandle;\n try {\n fileHandle = await open(expandedPath, 'r');\n const buffer = Buffer.alloc(512);\n await fileHandle.read(buffer, 0, 512, 0);\n\n // Check for binary magic numbers\n if (\n bufferStartsWith(buffer, MAGIC_NUMBERS.ELF) ||\n bufferStartsWith(buffer, MAGIC_NUMBERS.MACHO_32) ||\n bufferStartsWith(buffer, MAGIC_NUMBERS.MACHO_64) ||\n bufferStartsWith(buffer, MAGIC_NUMBERS.MACHO_UNIVERSAL) ||\n bufferStartsWith(buffer, MAGIC_NUMBERS.PE)\n ) {\n return true;\n }\n\n // If has execute permission but no magic number, might be a script\n // Check if it's actually a script (has shebang)\n if (hasExecutePermission) {\n const startsWithShebang = buffer[0] === 0x23 && buffer[1] === 0x21; // \"#!\"\n return !startsWithShebang; // Binary if no shebang\n }\n\n return false;\n } finally {\n if (fileHandle) {\n await fileHandle.close();\n }\n }\n } catch {\n // If any error occurs while checking the file (e.g. it does not exist,\n // cannot be accessed, or cannot be read), treat it as \"not an executable\n // binary\" and return false. Callers only rely on the boolean result.\n return false;\n }\n};\n\n/**\n * Check if file is a script based on shebang or extension\n */\nexport const isScriptFile = async (path: string): Promise<boolean> => {\n const expandedPath = expandPath(path);\n\n try {\n // Check extension first\n const hasScriptExtension = SCRIPT_EXTENSIONS.some((ext) => expandedPath.endsWith(ext));\n if (hasScriptExtension) {\n return true;\n }\n\n // Check for shebang\n const stats = await stat(expandedPath);\n if (stats.isDirectory()) {\n return false;\n }\n\n let fileHandle;\n try {\n fileHandle = await open(expandedPath, 'r');\n const buffer = Buffer.alloc(2);\n await fileHandle.read(buffer, 0, 2, 0);\n\n // Check for shebang \"#!\"\n return buffer[0] === 0x23 && buffer[1] === 0x21;\n } finally {\n if (fileHandle) {\n await fileHandle.close();\n }\n }\n } catch {\n // Any error while checking is treated as \"not a script\" to keep detection best-effort.\n // This includes file not found, permission denied, or read errors.\n return false;\n }\n};\n\n/**\n * Check if file should be excluded from bin directory tracking\n * Returns true for binary executables in ~/bin or ~/.local/bin\n * Returns false for script files\n */\nexport const shouldExcludeFromBin = async (path: string): Promise<boolean> => {\n const expandedPath = expandPath(path);\n\n // Check if file is in a bin directory by checking if parent directory is 'bin'\n // This matches both ~/bin and ~/.local/bin directories\n const parentDir = dirname(expandedPath);\n const parentBasename = basename(parentDir);\n \n const isInBinDir = parentBasename === 'bin';\n\n if (!isInBinDir) {\n return false;\n }\n\n // Check if it's a directory (don't exclude directories themselves)\n try {\n const stats = await stat(expandedPath);\n if (stats.isDirectory()) {\n return false;\n }\n } catch {\n return false;\n }\n\n // If it's a script, don't exclude it\n if (await isScriptFile(expandedPath)) {\n return false;\n }\n\n // If it's a binary executable, exclude it\n return await isBinaryExecutable(expandedPath);\n};\n\n/**\n * Get a human-readable description of why a file is being excluded\n */\nexport const getBinaryExclusionReason = async (path: string): Promise<string | null> => {\n if (await shouldExcludeFromBin(path)) {\n return 'Binary executable in bin directory';\n }\n return null;\n};\n\n","import { Command } from 'commander';\nimport { prompts, logger, withSpinner } from '../ui/index.js';\nimport {\n getTuckDir,\n expandPath,\n collapsePath,\n pathExists,\n} from '../lib/paths.js';\nimport { loadManifest, removeFileFromManifest, getTrackedFileBySource, getAllTrackedFiles } from '../lib/manifest.js';\nimport { deleteFileOrDir } from '../lib/files.js';\nimport { NotInitializedError, FileNotTrackedError } from '../errors.js';\nimport type { RemoveOptions } from '../types.js';\nimport { join } from 'path';\n\ninterface FileToRemove {\n id: string;\n source: string;\n destination: string;\n}\n\nconst validateAndPrepareFiles = async (\n paths: string[],\n tuckDir: string\n): Promise<FileToRemove[]> => {\n const filesToRemove: FileToRemove[] = [];\n\n for (const path of paths) {\n const expandedPath = expandPath(path);\n const collapsedPath = collapsePath(expandedPath);\n\n // Check if tracked\n const tracked = await getTrackedFileBySource(tuckDir, collapsedPath);\n if (!tracked) {\n throw new FileNotTrackedError(path);\n }\n\n filesToRemove.push({\n id: tracked.id,\n source: tracked.file.source,\n destination: join(tuckDir, tracked.file.destination),\n });\n }\n\n return filesToRemove;\n};\n\nconst removeFiles = async (\n filesToRemove: FileToRemove[],\n tuckDir: string,\n options: RemoveOptions\n): Promise<void> => {\n for (const file of filesToRemove) {\n // Remove from manifest\n await removeFileFromManifest(tuckDir, file.id);\n\n // Delete from repository if requested\n if (options.delete) {\n if (await pathExists(file.destination)) {\n await withSpinner(`Deleting ${file.source} from repository...`, async () => {\n await deleteFileOrDir(file.destination);\n });\n }\n }\n\n logger.success(`Removed ${file.source} from tracking`);\n if (options.delete) {\n logger.dim(' Also deleted from repository');\n }\n }\n};\n\nconst runInteractiveRemove = async (tuckDir: string): Promise<void> => {\n prompts.intro('tuck remove');\n\n // Get all tracked files\n const trackedFiles = await getAllTrackedFiles(tuckDir);\n const fileEntries = Object.entries(trackedFiles);\n\n if (fileEntries.length === 0) {\n prompts.log.warning('No files are currently tracked');\n prompts.outro('');\n return;\n }\n\n // Let user select files to remove\n const selectedFiles = await prompts.multiselect(\n 'Select files to stop tracking:',\n fileEntries.map(([id, file]) => ({\n value: id,\n label: file.source,\n hint: file.category,\n })),\n { required: true }\n );\n\n if (selectedFiles.length === 0) {\n prompts.cancel('No files selected');\n return;\n }\n\n // Ask if they want to delete from repo\n const shouldDelete = await prompts.confirm('Also delete files from repository?');\n\n // Confirm\n const confirm = await prompts.confirm(\n `Remove ${selectedFiles.length} ${selectedFiles.length === 1 ? 'file' : 'files'} from tracking?`,\n true\n );\n\n if (!confirm) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n // Prepare files to remove\n const filesToRemove: FileToRemove[] = selectedFiles.map((id) => {\n const file = trackedFiles[id as string];\n return {\n id: id as string,\n source: file.source,\n destination: join(tuckDir, file.destination),\n };\n });\n\n // Remove files\n await removeFiles(filesToRemove, tuckDir, { delete: shouldDelete });\n\n prompts.outro(`Removed ${selectedFiles.length} ${selectedFiles.length === 1 ? 'file' : 'files'}`);\n logger.info(\"Run 'tuck sync' to commit changes\");\n};\n\nconst runRemove = async (paths: string[], options: RemoveOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n if (paths.length === 0) {\n await runInteractiveRemove(tuckDir);\n return;\n }\n\n // Validate and prepare files\n const filesToRemove = await validateAndPrepareFiles(paths, tuckDir);\n\n // Remove files\n await removeFiles(filesToRemove, tuckDir, options);\n\n logger.blank();\n logger.success(`Removed ${filesToRemove.length} ${filesToRemove.length === 1 ? 'item' : 'items'} from tracking`);\n logger.info(\"Run 'tuck sync' to commit changes\");\n};\n\nexport const removeCommand = new Command('remove')\n .description('Stop tracking dotfiles')\n .argument('[paths...]', 'Paths to dotfiles to untrack')\n .option('--delete', 'Also delete from tuck repository')\n .option('--keep-original', \"Don't restore symlinks to regular files\")\n .action(async (paths: string[], options: RemoveOptions) => {\n await runRemove(paths, options);\n });\n","export { initCommand } from './init.js';\nexport { addCommand } from './add.js';\nexport { removeCommand } from './remove.js';\nexport { syncCommand } from './sync.js';\nexport { pushCommand } from './push.js';\nexport { pullCommand } from './pull.js';\nexport { restoreCommand } from './restore.js';\nexport { statusCommand } from './status.js';\nexport { listCommand } from './list.js';\nexport { diffCommand } from './diff.js';\nexport { configCommand } from './config.js';\nexport { applyCommand } from './apply.js';\nexport { undoCommand } from './undo.js';\nexport { scanCommand } from './scan.js';\nexport { secretsCommand } from './secrets.js';\n","import { Command } from 'commander';\nimport { prompts, logger, withSpinner, colors as c } from '../ui/index.js';\nimport { getTuckDir } from '../lib/paths.js';\nimport { loadManifest } from '../lib/manifest.js';\nimport { checkLocalMode, showLocalModeWarningForPush } from '../lib/remoteChecks.js';\nimport {\n push,\n hasRemote,\n getRemoteUrl,\n getStatus,\n getCurrentBranch,\n addRemote,\n} from '../lib/git.js';\nimport { NotInitializedError, GitError } from '../errors.js';\nimport type { PushOptions } from '../types.js';\n\nconst runInteractivePush = async (tuckDir: string): Promise<void> => {\n prompts.intro('tuck push');\n\n // Check for local-only mode\n if (await checkLocalMode(tuckDir)) {\n await showLocalModeWarningForPush();\n prompts.outro('');\n return;\n }\n\n // Check if remote exists\n const hasRemoteRepo = await hasRemote(tuckDir);\n\n if (!hasRemoteRepo) {\n prompts.log.warning('No remote configured');\n\n const addRemoteNow = await prompts.confirm('Would you like to add a remote?');\n if (!addRemoteNow) {\n prompts.cancel('No remote to push to');\n return;\n }\n\n const remoteUrl = await prompts.text('Enter remote URL:', {\n placeholder: 'git@github.com:user/dotfiles.git',\n validate: (value) => {\n if (!value) return 'Remote URL is required';\n return undefined;\n },\n });\n\n await addRemote(tuckDir, 'origin', remoteUrl);\n prompts.log.success('Remote added');\n }\n\n // Get current status\n const status = await getStatus(tuckDir);\n const branch = await getCurrentBranch(tuckDir);\n const remoteUrl = await getRemoteUrl(tuckDir);\n\n if (status.ahead === 0 && status.tracking) {\n prompts.log.success('Already up to date with remote');\n return;\n }\n\n // Show what will be pushed\n console.log();\n console.log(c.dim('Remote:'), remoteUrl);\n console.log(c.dim('Branch:'), branch);\n\n if (status.ahead > 0) {\n console.log(c.dim('Commits:'), c.green(`↑ ${status.ahead} to push`));\n }\n\n if (status.behind > 0) {\n console.log(c.dim('Warning:'), c.yellow(`↓ ${status.behind} commits behind remote`));\n\n const pullFirst = await prompts.confirm('Pull changes first?', true);\n if (pullFirst) {\n prompts.log.info(\"Run 'tuck pull' first, then push\");\n return;\n }\n }\n\n console.log();\n\n // Confirm\n const confirm = await prompts.confirm('Push to remote?', true);\n if (!confirm) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n // Push\n const needsUpstream = !status.tracking;\n\n try {\n await withSpinner('Pushing...', async () => {\n await push(tuckDir, {\n setUpstream: needsUpstream,\n branch: needsUpstream ? branch : undefined,\n });\n });\n prompts.log.success('Pushed successfully!');\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n\n // Provide specific guidance based on common errors\n if (errorMsg.includes('Permission denied') || errorMsg.includes('publickey')) {\n prompts.log.error('Authentication failed');\n prompts.log.info('Check your SSH keys with: ssh -T git@github.com');\n prompts.log.info('Or try switching to HTTPS: git remote set-url origin https://...');\n } else if (errorMsg.includes('Could not resolve host') || errorMsg.includes('Network')) {\n prompts.log.error('Network error - could not reach remote');\n prompts.log.info('Check your internet connection and try again');\n } else if (errorMsg.includes('rejected') || errorMsg.includes('non-fast-forward')) {\n prompts.log.error('Push rejected - remote has changes');\n prompts.log.info(\"Run 'tuck pull' first, then push again\");\n prompts.log.info(\"Or use 'tuck push --force' to overwrite (use with caution)\");\n } else {\n prompts.log.error(`Push failed: ${errorMsg}`);\n }\n return;\n }\n\n if (remoteUrl) {\n // Extract repo URL for display\n let viewUrl = remoteUrl;\n if (remoteUrl.startsWith('git@github.com:')) {\n viewUrl = remoteUrl.replace('git@github.com:', 'https://github.com/').replace('.git', '');\n }\n console.log();\n console.log(c.dim('View at:'), c.cyan(viewUrl));\n }\n\n prompts.outro('');\n};\n\nconst runPush = async (options: PushOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Check for local-only mode\n if (await checkLocalMode(tuckDir)) {\n throw new GitError(\n 'Cannot push in local-only mode',\n \"Run 'tuck config remote' to configure a remote repository\"\n );\n }\n\n // If no options, run interactive\n if (!options.force && !options.setUpstream) {\n await runInteractivePush(tuckDir);\n return;\n }\n\n // Check if remote exists\n const hasRemoteRepo = await hasRemote(tuckDir);\n if (!hasRemoteRepo) {\n throw new GitError('No remote configured', \"Run 'tuck init -r <url>' or add a remote manually\");\n }\n\n const branch = await getCurrentBranch(tuckDir);\n\n try {\n await withSpinner('Pushing...', async () => {\n await push(tuckDir, {\n force: options.force,\n setUpstream: Boolean(options.setUpstream),\n branch: options.setUpstream || branch,\n });\n });\n logger.success('Pushed successfully!');\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n\n if (errorMsg.includes('Permission denied') || errorMsg.includes('publickey')) {\n throw new GitError('Authentication failed', 'Check your SSH keys: ssh -T git@github.com');\n } else if (errorMsg.includes('Could not resolve host') || errorMsg.includes('Network')) {\n throw new GitError('Network error', 'Check your internet connection');\n } else if (errorMsg.includes('rejected') || errorMsg.includes('non-fast-forward')) {\n throw new GitError('Push rejected', \"Run 'tuck pull' first, or use --force\");\n } else {\n throw new GitError('Push failed', errorMsg);\n }\n }\n};\n\nexport const pushCommand = new Command('push')\n .description('Push changes to remote repository')\n .option('-f, --force', 'Force push')\n .option('--set-upstream <name>', 'Set upstream branch')\n .action(async (options: PushOptions) => {\n await runPush(options);\n });\n","/**\n * Remote Configuration Checks\n *\n * Shared utilities for checking remote configuration and local mode.\n */\n\nimport { prompts } from '../ui/index.js';\nimport { loadConfig } from './config.js';\n\n/**\n * Check if tuck is in local-only mode\n */\nexport const checkLocalMode = async (tuckDir: string): Promise<boolean> => {\n try {\n const config = await loadConfig(tuckDir);\n if (config.remote?.mode === 'local') {\n return true;\n }\n } catch {\n // Config not found or invalid - proceed with remote operations\n }\n return false;\n};\n\n/**\n * Show local mode warning (for pull command)\n */\nexport const showLocalModeWarningForPull = async (): Promise<void> => {\n prompts.log.warning('Tuck is configured for local-only mode (no remote sync).');\n console.log();\n prompts.note(\n 'Your dotfiles are tracked locally but not synced to a remote.\\n\\n' +\n 'To enable remote sync, run:\\n' +\n ' tuck config remote\\n\\n' +\n 'Or re-initialize with:\\n' +\n ' tuck init',\n 'Local Mode'\n );\n};\n\n/**\n * Show local mode warning and offer to configure remote (for push command)\n */\nexport const showLocalModeWarningForPush = async (): Promise<boolean> => {\n prompts.log.warning('Tuck is configured for local-only mode (no remote sync).');\n console.log();\n prompts.note(\n 'Your dotfiles are tracked locally but not synced to a remote.\\n\\n' +\n 'To enable remote sync, run:\\n' +\n ' tuck config remote\\n\\n' +\n 'Or re-initialize with:\\n' +\n ' tuck init',\n 'Local Mode'\n );\n console.log();\n\n const configureNow = await prompts.confirm('Would you like to configure a remote now?');\n\n if (configureNow) {\n prompts.log.info(\"Run 'tuck config remote' to set up a remote repository.\");\n }\n\n return configureNow;\n};\n","import { Command } from 'commander';\nimport { prompts, logger, withSpinner, colors as c } from '../ui/index.js';\nimport { getTuckDir } from '../lib/paths.js';\nimport { loadManifest } from '../lib/manifest.js';\nimport { checkLocalMode, showLocalModeWarningForPull } from '../lib/remoteChecks.js';\nimport { pull, fetch, hasRemote, getRemoteUrl, getStatus, getCurrentBranch } from '../lib/git.js';\nimport { NotInitializedError, GitError } from '../errors.js';\nimport type { PullOptions } from '../types.js';\n\nconst runInteractivePull = async (tuckDir: string): Promise<void> => {\n prompts.intro('tuck pull');\n\n // Check for local-only mode\n if (await checkLocalMode(tuckDir)) {\n await showLocalModeWarningForPull();\n prompts.outro('');\n return;\n }\n\n // Check if remote exists\n const hasRemoteRepo = await hasRemote(tuckDir);\n if (!hasRemoteRepo) {\n prompts.log.error('No remote configured');\n prompts.note(\"Run 'tuck init -r <url>' or add a remote manually\", 'Tip');\n return;\n }\n\n // Fetch first to get latest remote status\n await withSpinner('Fetching...', async () => {\n await fetch(tuckDir);\n });\n\n // Get current status\n const status = await getStatus(tuckDir);\n const branch = await getCurrentBranch(tuckDir);\n const remoteUrl = await getRemoteUrl(tuckDir);\n\n // Show status\n console.log();\n console.log(c.dim('Remote:'), remoteUrl);\n console.log(c.dim('Branch:'), branch);\n\n if (status.behind === 0) {\n prompts.log.success('Already up to date');\n return;\n }\n\n console.log(c.dim('Commits:'), c.yellow(`↓ ${status.behind} to pull`));\n\n if (status.ahead > 0) {\n console.log(\n c.dim('Note:'),\n c.yellow(`You also have ${status.ahead} local commit${status.ahead > 1 ? 's' : ''} to push`)\n );\n }\n\n // Check for local changes\n if (status.modified.length > 0 || status.staged.length > 0) {\n console.log();\n prompts.log.warning('You have uncommitted changes');\n console.log(c.dim('Modified:'), status.modified.join(', '));\n\n const continueAnyway = await prompts.confirm('Pull anyway? (may cause merge conflicts)');\n if (!continueAnyway) {\n prompts.cancel(\"Commit or stash your changes first with 'tuck sync'\");\n return;\n }\n }\n\n console.log();\n\n // Ask about rebase\n const useRebase = await prompts.confirm('Use rebase instead of merge?');\n\n // Pull\n await withSpinner('Pulling...', async () => {\n await pull(tuckDir, { rebase: useRebase });\n });\n\n prompts.log.success('Pulled successfully!');\n\n // Ask about restore\n const shouldRestore = await prompts.confirm('Restore updated dotfiles to system?', true);\n if (shouldRestore) {\n prompts.note(\"Run 'tuck restore --all' to restore all dotfiles\", 'Next step');\n }\n\n prompts.outro('');\n};\n\nconst runPull = async (options: PullOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Check for local-only mode\n if (await checkLocalMode(tuckDir)) {\n throw new GitError(\n 'Cannot pull in local-only mode',\n \"Run 'tuck config remote' to configure a remote repository\"\n );\n }\n\n // If no options, run interactive\n if (!options.rebase && !options.restore) {\n await runInteractivePull(tuckDir);\n return;\n }\n\n // Check if remote exists\n const hasRemoteRepo = await hasRemote(tuckDir);\n if (!hasRemoteRepo) {\n throw new GitError('No remote configured', \"Run 'tuck init -r <url>' or add a remote manually\");\n }\n\n // Fetch first\n await withSpinner('Fetching...', async () => {\n await fetch(tuckDir);\n });\n\n // Pull\n await withSpinner('Pulling...', async () => {\n await pull(tuckDir, { rebase: options.rebase });\n });\n\n logger.success('Pulled successfully!');\n\n if (options.restore) {\n logger.info(\"Run 'tuck restore --all' to restore dotfiles\");\n }\n};\n\nexport const pullCommand = new Command('pull')\n .description('Pull changes from remote')\n .option('--rebase', 'Pull with rebase')\n .option('--restore', 'Also restore files to system after pull')\n .action(async (options: PullOptions) => {\n await runPull(options);\n });\n","/**\n * Status command for tuck CLI\n * Shows current tracking status in a compact, modern layout\n */\n\nimport { Command } from 'commander';\nimport boxen from 'boxen';\nimport logSymbols from 'log-symbols';\nimport figures from 'figures';\nimport { colors as c, boxStyles, indent, formatStatus, categoryStyles } from '../ui/index.js';\nimport { prompts } from '../ui/prompts.js';\nimport { getTuckDir, collapsePath, expandPath, pathExists } from '../lib/paths.js';\nimport { loadManifest, getAllTrackedFiles } from '../lib/manifest.js';\nimport { getStatus, hasRemote, getRemoteUrl, getCurrentBranch } from '../lib/git.js';\nimport { getFileChecksum } from '../lib/files.js';\nimport { loadTuckignore } from '../lib/tuckignore.js';\nimport { NotInitializedError } from '../errors.js';\nimport { VERSION } from '../constants.js';\nimport type { StatusOptions, FileChange } from '../types.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface TuckStatus {\n tuckDir: string;\n branch: string;\n remote?: string;\n remoteStatus: 'up-to-date' | 'ahead' | 'behind' | 'diverged' | 'no-remote';\n ahead: number;\n behind: number;\n trackedCount: number;\n categoryCounts: Record<string, number>;\n changes: FileChange[];\n gitChanges: {\n staged: string[];\n modified: string[];\n untracked: string[];\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Status Detection\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst detectFileChanges = async (tuckDir: string): Promise<FileChange[]> => {\n const files = await getAllTrackedFiles(tuckDir);\n const ignoredPaths = await loadTuckignore(tuckDir);\n const changes: FileChange[] = [];\n\n for (const [, file] of Object.entries(files)) {\n if (ignoredPaths.has(file.source)) {\n continue;\n }\n\n const sourcePath = expandPath(file.source);\n\n if (!(await pathExists(sourcePath))) {\n changes.push({\n path: file.source,\n status: 'deleted',\n source: file.source,\n destination: file.destination,\n });\n continue;\n }\n\n try {\n const sourceChecksum = await getFileChecksum(sourcePath);\n if (sourceChecksum !== file.checksum) {\n changes.push({\n path: file.source,\n status: 'modified',\n source: file.source,\n destination: file.destination,\n });\n }\n } catch {\n changes.push({\n path: file.source,\n status: 'modified',\n source: file.source,\n destination: file.destination,\n });\n }\n }\n\n return changes;\n};\n\nconst getFullStatus = async (tuckDir: string): Promise<TuckStatus> => {\n const manifest = await loadManifest(tuckDir);\n const gitStatus = await getStatus(tuckDir);\n const branch = await getCurrentBranch(tuckDir);\n const hasRemoteRepo = await hasRemote(tuckDir);\n const remoteUrl = hasRemoteRepo ? await getRemoteUrl(tuckDir) : undefined;\n\n let remoteStatus: TuckStatus['remoteStatus'] = 'no-remote';\n if (hasRemoteRepo) {\n if (gitStatus.ahead > 0 && gitStatus.behind > 0) {\n remoteStatus = 'diverged';\n } else if (gitStatus.ahead > 0) {\n remoteStatus = 'ahead';\n } else if (gitStatus.behind > 0) {\n remoteStatus = 'behind';\n } else {\n remoteStatus = 'up-to-date';\n }\n }\n\n const fileChanges = await detectFileChanges(tuckDir);\n\n const categoryCounts: Record<string, number> = {};\n for (const file of Object.values(manifest.files)) {\n categoryCounts[file.category] = (categoryCounts[file.category] || 0) + 1;\n }\n\n return {\n tuckDir,\n branch,\n remote: remoteUrl || undefined,\n remoteStatus,\n ahead: gitStatus.ahead,\n behind: gitStatus.behind,\n trackedCount: Object.keys(manifest.files).length,\n categoryCounts,\n changes: fileChanges,\n gitChanges: {\n staged: gitStatus.staged,\n modified: gitStatus.modified,\n untracked: gitStatus.untracked,\n },\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output Formatting\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst formatRemoteUrl = (url: string): string => {\n // Shorten common patterns\n return url\n .replace(/^https?:\\/\\//, '')\n .replace(/\\.git$/, '')\n .replace(/^github\\.com\\//, '');\n};\n\nconst printStatus = (status: TuckStatus): void => {\n // Header box\n const headerLines: string[] = [\n `${c.brandBold('tuck')} ${c.muted(`v${VERSION}`)}`,\n '',\n `${c.muted('Repository:')} ${collapsePath(status.tuckDir)}`,\n `${c.muted('Branch:')} ${c.brand(status.branch)}`,\n ];\n\n if (status.remote) {\n headerLines.push(`${c.muted('Remote:')} ${formatRemoteUrl(status.remote)}`);\n } else {\n headerLines.push(`${c.muted('Remote:')} ${c.warning('not configured')}`);\n }\n\n console.log(boxen(headerLines.join('\\n'), boxStyles.header));\n\n // Remote status\n if (status.remote) {\n console.log();\n switch (status.remoteStatus) {\n case 'up-to-date':\n console.log(logSymbols.success, c.success('Up to date with remote'));\n break;\n case 'ahead':\n console.log(\n c.warning(figures.arrowUp),\n c.warning(`${status.ahead} commit${status.ahead > 1 ? 's' : ''} ahead`)\n );\n break;\n case 'behind':\n console.log(\n c.warning(figures.arrowDown),\n c.warning(`${status.behind} commit${status.behind > 1 ? 's' : ''} behind`)\n );\n break;\n case 'diverged':\n console.log(\n logSymbols.warning,\n c.error(`Diverged (${status.ahead} ahead, ${status.behind} behind)`)\n );\n break;\n }\n }\n\n // Tracked files summary\n console.log();\n console.log(c.bold(`${status.trackedCount} files tracked`));\n\n // Category breakdown (inline, compact)\n const categoryOrder = ['shell', 'git', 'editors', 'terminal', 'ssh', 'misc'];\n const sortedCategories = Object.keys(status.categoryCounts).sort((a, b) => {\n const aIdx = categoryOrder.indexOf(a);\n const bIdx = categoryOrder.indexOf(b);\n if (aIdx === -1 && bIdx === -1) return a.localeCompare(b);\n if (aIdx === -1) return 1;\n if (bIdx === -1) return -1;\n return aIdx - bIdx;\n });\n\n if (sortedCategories.length > 0) {\n const categoryLine = sortedCategories\n .map((cat) => {\n const style = categoryStyles[cat] || categoryStyles.misc;\n const count = status.categoryCounts[cat];\n return `${style.color(style.icon)} ${cat}: ${count}`;\n })\n .join(' ');\n console.log(c.muted(indent() + categoryLine));\n }\n\n // File changes\n if (status.changes.length > 0) {\n console.log();\n console.log(c.bold('Changes:'));\n for (const change of status.changes) {\n const statusText = formatStatus(change.status);\n console.log(`${indent()}${statusText} ${c.brand(change.path)}`);\n }\n }\n\n // Git changes\n const hasGitChanges =\n status.gitChanges.staged.length > 0 ||\n status.gitChanges.modified.length > 0 ||\n status.gitChanges.untracked.length > 0;\n\n if (hasGitChanges) {\n console.log();\n console.log(c.bold('Repository:'));\n\n if (status.gitChanges.staged.length > 0) {\n console.log(c.success(`${indent()}Staged:`));\n status.gitChanges.staged.forEach((f) =>\n console.log(c.success(`${indent()}${indent()}+ ${f}`))\n );\n }\n\n if (status.gitChanges.modified.length > 0) {\n console.log(c.warning(`${indent()}Modified:`));\n status.gitChanges.modified.forEach((f) =>\n console.log(c.warning(`${indent()}${indent()}~ ${f}`))\n );\n }\n\n if (status.gitChanges.untracked.length > 0) {\n console.log(c.muted(`${indent()}Untracked:`));\n status.gitChanges.untracked.forEach((f) =>\n console.log(c.muted(`${indent()}${indent()}? ${f}`))\n );\n }\n }\n\n console.log();\n\n // Next step suggestion\n if (status.changes.length > 0) {\n prompts.note(\"Run 'tuck sync' to commit changes\", 'Next');\n } else if (status.remoteStatus === 'ahead') {\n prompts.note(\"Run 'tuck push' to push changes\", 'Next');\n } else if (status.remoteStatus === 'behind') {\n prompts.note(\"Run 'tuck pull' to pull changes\", 'Next');\n } else if (status.trackedCount === 0) {\n prompts.note(\"Run 'tuck add <path>' to start tracking\", 'Next');\n } else {\n prompts.outro('Everything up to date');\n }\n};\n\nconst printShortStatus = (status: TuckStatus): void => {\n const parts: string[] = [];\n\n parts.push(`[${status.branch}]`);\n\n if (status.remoteStatus === 'ahead') {\n parts.push(c.warning(`${figures.arrowUp}${status.ahead}`));\n } else if (status.remoteStatus === 'behind') {\n parts.push(c.warning(`${figures.arrowDown}${status.behind}`));\n } else if (status.remoteStatus === 'diverged') {\n parts.push(c.error(`${figures.arrowUp}${status.ahead}${figures.arrowDown}${status.behind}`));\n }\n\n if (status.changes.length > 0) {\n const modified = status.changes.filter((ch) => ch.status === 'modified').length;\n const deleted = status.changes.filter((ch) => ch.status === 'deleted').length;\n if (modified > 0) parts.push(c.warning(`~${modified}`));\n if (deleted > 0) parts.push(c.error(`-${deleted}`));\n }\n\n parts.push(c.muted(`(${status.trackedCount} tracked)`));\n\n console.log(parts.join(' '));\n};\n\nconst printJsonStatus = (status: TuckStatus): void => {\n console.log(JSON.stringify(status, null, 2));\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Command Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst runStatus = async (options: StatusOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n const status = await getFullStatus(tuckDir);\n\n if (options.json) {\n printJsonStatus(status);\n } else if (options.short) {\n printShortStatus(status);\n } else {\n printStatus(status);\n }\n};\n\nexport const statusCommand = new Command('status')\n .description('Show current tracking status')\n .option('--short', 'Short format')\n .option('--json', 'Output as JSON')\n .action(async (options: StatusOptions) => {\n await runStatus(options);\n });\n","import { Command } from 'commander';\nimport { prompts, logger, formatCount, colors as c } from '../ui/index.js';\nimport { getTuckDir } from '../lib/paths.js';\nimport { loadManifest, getAllTrackedFiles } from '../lib/manifest.js';\nimport { NotInitializedError } from '../errors.js';\nimport { CATEGORIES } from '../constants.js';\nimport type { ListOptions } from '../types.js';\n\ninterface CategoryGroup {\n name: string;\n icon: string;\n files: { id: string; source: string; destination: string; isDir: boolean }[];\n}\n\nconst groupByCategory = async (tuckDir: string): Promise<CategoryGroup[]> => {\n const files = await getAllTrackedFiles(tuckDir);\n const groups: Map<string, CategoryGroup> = new Map();\n\n for (const [id, file] of Object.entries(files)) {\n const category = file.category;\n const categoryConfig = CATEGORIES[category] || { icon: '📄' };\n\n if (!groups.has(category)) {\n groups.set(category, {\n name: category,\n icon: categoryConfig.icon,\n files: [],\n });\n }\n\n groups.get(category)!.files.push({\n id,\n source: file.source,\n destination: file.destination,\n isDir: file.destination.endsWith('/') || file.destination.includes('nvim'),\n });\n }\n\n // Sort groups by name and files within each group\n return Array.from(groups.values())\n .sort((a, b) => a.name.localeCompare(b.name))\n .map((group) => ({\n ...group,\n files: group.files.sort((a, b) => a.source.localeCompare(b.source)),\n }));\n};\n\nconst printList = (groups: CategoryGroup[]): void => {\n prompts.intro('tuck list');\n\n if (groups.length === 0) {\n prompts.log.warning('No files are currently tracked');\n prompts.note(\"Run 'tuck add <path>' to start tracking files\", 'Tip');\n return;\n }\n\n let totalFiles = 0;\n\n for (const group of groups) {\n const fileCount = group.files.length;\n totalFiles += fileCount;\n\n console.log();\n console.log(\n c.bold(`${group.icon} ${group.name}`) + c.dim(` (${formatCount(fileCount, 'file')})`)\n );\n\n group.files.forEach((file, index) => {\n const isLast = index === group.files.length - 1;\n const prefix = isLast ? '└── ' : '├── ';\n const name = file.source.split('/').pop() || file.source;\n const arrow = c.dim(' → ');\n const dest = c.dim(file.source);\n\n console.log(c.dim(prefix) + c.cyan(name) + arrow + dest);\n });\n }\n\n console.log();\n prompts.outro(`Total: ${formatCount(totalFiles, 'tracked item')}`);\n};\n\nconst printPathsOnly = (groups: CategoryGroup[]): void => {\n for (const group of groups) {\n for (const file of group.files) {\n console.log(file.source);\n }\n }\n};\n\nconst printJson = (groups: CategoryGroup[]): void => {\n const output = groups.reduce(\n (acc, group) => {\n acc[group.name] = group.files.map((f) => ({\n source: f.source,\n destination: f.destination,\n }));\n return acc;\n },\n {} as Record<string, { source: string; destination: string }[]>\n );\n\n console.log(JSON.stringify(output, null, 2));\n};\n\nconst runList = async (options: ListOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n let groups = await groupByCategory(tuckDir);\n\n // Filter by category if specified\n if (options.category) {\n groups = groups.filter((g) => g.name === options.category);\n if (groups.length === 0) {\n logger.warning(`No files found in category: ${options.category}`);\n return;\n }\n }\n\n // Output based on format\n if (options.json) {\n printJson(groups);\n } else if (options.paths) {\n printPathsOnly(groups);\n } else {\n printList(groups);\n }\n};\n\nexport const listCommand = new Command('list')\n .description('List all tracked files')\n .option('-c, --category <name>', 'Filter by category')\n .option('--paths', 'Show only paths')\n .option('--json', 'Output as JSON')\n .action(async (options: ListOptions) => {\n await runList(options);\n });\n","import { Command } from 'commander';\nimport { join } from 'path';\nimport { prompts, logger } from '../ui/index.js';\nimport { colors as c } from '../ui/theme.js';\nimport { getTuckDir, expandPath, pathExists, collapsePath, isDirectory } from '../lib/paths.js';\nimport { loadManifest, getAllTrackedFiles, getTrackedFileBySource } from '../lib/manifest.js';\nimport { getDiff } from '../lib/git.js';\nimport {\n getFileChecksum,\n checkFileSizeThreshold,\n formatFileSize,\n getDirectoryFiles,\n} from '../lib/files.js';\nimport { NotInitializedError, FileNotFoundError, PermissionError } from '../errors.js';\nimport { isBinaryExecutable } from '../lib/binary.js';\nimport { isIgnored } from '../lib/tuckignore.js';\nimport type { DiffOptions } from '../types.js';\nimport { readFile } from 'fs/promises';\n\ninterface FileDiff {\n source: string;\n destination: string;\n hasChanges: boolean;\n isBinary?: boolean;\n isDirectory?: boolean;\n fileCount?: number;\n systemSize?: number;\n repoSize?: number;\n systemContent?: string;\n repoContent?: string;\n}\n\nconst isBinary = async (path: string): Promise<boolean> => {\n if (!(await pathExists(path))) {\n return false;\n }\n return await isBinaryExecutable(path);\n};\n\nconst getFileDiff = async (tuckDir: string, source: string): Promise<FileDiff | null> => {\n const tracked = await getTrackedFileBySource(tuckDir, source);\n if (!tracked) {\n throw new FileNotFoundError(`Not tracked: ${source}`);\n }\n\n const systemPath = expandPath(source);\n const repoPath = join(tuckDir, tracked.file.destination);\n\n const diff: FileDiff = {\n source,\n destination: tracked.file.destination,\n hasChanges: false,\n };\n\n const systemExists = await pathExists(systemPath);\n const repoExists = await pathExists(repoPath);\n\n // Check if system file exists\n if (!systemExists) {\n diff.hasChanges = true;\n if (repoExists) {\n // Check if repo file is a directory\n if (await isDirectory(repoPath)) {\n diff.isDirectory = true;\n const files = await getDirectoryFiles(repoPath);\n diff.fileCount = files.length;\n } else {\n const repoContent = await readFile(repoPath, 'utf-8');\n diff.repoContent = repoContent;\n diff.repoSize = repoContent.length;\n }\n }\n return diff;\n }\n\n // Check if repo file exists\n if (!repoExists) {\n diff.hasChanges = true;\n // Check if system file is a directory\n if (await isDirectory(systemPath)) {\n diff.isDirectory = true;\n const files = await getDirectoryFiles(systemPath);\n diff.fileCount = files.length;\n } else {\n const systemContent = await readFile(systemPath, 'utf-8');\n diff.systemContent = systemContent;\n diff.systemSize = systemContent.length;\n }\n return diff;\n }\n\n // Check if directory (both exist now)\n const systemIsDir = await isDirectory(systemPath);\n const repoIsDir = await isDirectory(repoPath);\n\n if (systemIsDir || repoIsDir) {\n diff.isDirectory = true;\n\n // Get file counts for directory summary\n if (systemIsDir) {\n const files = await getDirectoryFiles(systemPath);\n diff.fileCount = files.length;\n }\n if (repoIsDir) {\n const files = await getDirectoryFiles(repoPath);\n diff.fileCount = (diff.fileCount || 0) + files.length;\n }\n\n // Compare checksums for directories too\n const systemChecksum = await getFileChecksum(systemPath);\n const repoChecksum = await getFileChecksum(repoPath);\n diff.hasChanges = systemChecksum !== repoChecksum;\n\n return diff;\n }\n\n // Check if binary\n const systemIsBinary = await isBinary(systemPath);\n const repoIsBinary = await isBinary(repoPath);\n\n if (systemIsBinary || repoIsBinary) {\n diff.isBinary = true;\n\n // Compare binary files using checksums\n const systemChecksum = await getFileChecksum(systemPath);\n const repoChecksum = await getFileChecksum(repoPath);\n diff.hasChanges = systemChecksum !== repoChecksum;\n\n try {\n const systemBuffer = await readFile(systemPath);\n diff.systemSize = systemBuffer.length;\n } catch {\n // Ignore read errors for binaries\n }\n try {\n const repoBuffer = await readFile(repoPath);\n diff.repoSize = repoBuffer.length;\n } catch {\n // Ignore read errors for binaries\n }\n return diff;\n }\n\n // Check file size for large files\n try {\n const systemSizeCheck = await checkFileSizeThreshold(systemPath);\n const repoSizeCheck = await checkFileSizeThreshold(repoPath);\n\n diff.systemSize = systemSizeCheck.size;\n diff.repoSize = repoSizeCheck.size;\n } catch {\n // Size check failed, continue with diff\n }\n\n // Compare checksums for text files\n const systemChecksum = await getFileChecksum(systemPath);\n const repoChecksum = await getFileChecksum(repoPath);\n\n if (systemChecksum !== repoChecksum) {\n diff.hasChanges = true;\n diff.systemContent = await readFile(systemPath, 'utf-8');\n diff.repoContent = await readFile(repoPath, 'utf-8');\n }\n\n return diff;\n};\n\nconst formatUnifiedDiff = (diff: FileDiff): string => {\n const lines: string[] = [];\n\n lines.push(c.bold(`--- a/${diff.source} (system)`));\n lines.push(c.bold(`+++ b/${diff.source} (repository)`));\n\n if (diff.isBinary) {\n const sysSize = diff.systemSize ? formatFileSize(diff.systemSize) : '0 B';\n const repoSize = diff.repoSize ? formatFileSize(diff.repoSize) : '0 B';\n lines.push(c.dim('Binary files differ'));\n lines.push(c.dim(` System: ${sysSize}`));\n lines.push(c.dim(` Repo: ${repoSize}`));\n return lines.join('\\n');\n }\n\n if (diff.isDirectory) {\n const fileCount = diff.fileCount || 0;\n lines.push(c.dim('Directory content changed'));\n lines.push(c.dim(` Contains ${fileCount} file${fileCount > 1 ? 's' : ''}`));\n return lines.join('\\n');\n }\n\n const { systemContent, repoContent } = diff;\n\n // Check if systemContent is explicitly undefined (missing) vs empty string\n const systemMissing = systemContent === undefined;\n const repoMissing = repoContent === undefined;\n\n if (systemMissing && !repoMissing) {\n // File only in repo\n lines.push(c.red('File missing on system'));\n lines.push(c.dim('Repository content:'));\n repoContent!.split('\\n').forEach((line) => {\n lines.push(c.green(`+ ${line}`));\n });\n } else if (!systemMissing && repoMissing) {\n // File only on system\n lines.push(c.yellow('File not yet synced to repository'));\n lines.push(c.dim('System content:'));\n systemContent!.split('\\n').forEach((line) => {\n lines.push(c.red(`- ${line}`));\n });\n } else if (!systemMissing && !repoMissing) {\n // Both files exist (may be empty)\n const CONTEXT_LINES = 3;\n const systemLines = systemContent!.split('\\n');\n const repoLines = repoContent!.split('\\n');\n\n const maxLines = Math.max(systemLines.length, repoLines.length);\n\n let inDiff = false;\n let diffStart = 0;\n\n for (let i = 0; i < maxLines; i++) {\n const sysLine = systemLines[i];\n const repoLine = repoLines[i];\n\n if (sysLine !== repoLine) {\n if (!inDiff) {\n inDiff = true;\n diffStart = i;\n const startLine = Math.max(0, diffStart - CONTEXT_LINES + 1);\n const contextLineCount = Math.min(diffStart, CONTEXT_LINES);\n const endLine = Math.min(maxLines, diffStart + CONTEXT_LINES + 1);\n\n lines.push(\n c.cyan(\n `@@ -${startLine + 1},${contextLineCount + 1} +${startLine + 1},${endLine - startLine} @@`\n )\n );\n\n // Print context lines before diff\n for (let j = startLine; j < i; j++) {\n const ctxLine = systemLines[j];\n if (ctxLine !== undefined) {\n lines.push(c.dim(` ${ctxLine}`));\n }\n }\n }\n\n if (sysLine !== undefined) {\n lines.push(c.red(`- ${sysLine}`));\n }\n if (repoLine !== undefined) {\n lines.push(c.green(`+ ${repoLine}`));\n }\n } else if (inDiff) {\n // Show context lines after diff changes\n if (sysLine === repoLine && sysLine !== undefined) {\n lines.push(c.dim(` ${sysLine}`));\n }\n } else {\n // Exit diff context after matching lines\n inDiff = false;\n }\n }\n }\n\n return lines.join('\\n');\n};\n\nconst runDiff = async (paths: string[], options: DiffOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Verify tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // If --staged, show git diff\n if (options.staged) {\n const diff = await getDiff(tuckDir, { staged: true, stat: options.stat });\n if (diff) {\n console.log(diff);\n } else {\n logger.info('No staged changes');\n }\n return;\n }\n\n // Get all tracked files\n const allFiles = await getAllTrackedFiles(tuckDir);\n const changedFiles: FileDiff[] = [];\n\n // If no paths specified, check all files\n const filesToCheck =\n paths.length === 0\n ? Object.values(allFiles)\n : paths.map((path) => {\n const expandedPath = expandPath(path);\n const collapsedPath = collapsePath(expandedPath);\n const tracked = Object.entries(allFiles).find(([, f]) => f.source === collapsedPath);\n if (!tracked) {\n throw new FileNotFoundError(`Not tracked: ${path}`);\n }\n return tracked[1];\n });\n\n // Check each file for changes\n for (const file of filesToCheck) {\n // Skip if category filter is set and doesn't match\n if (options.category && file.category !== options.category) {\n continue;\n }\n\n // Skip if in .tuckignore\n if (await isIgnored(tuckDir, file.source)) {\n continue;\n }\n\n try {\n const diff = await getFileDiff(tuckDir, file.source);\n if (diff && diff.hasChanges) {\n changedFiles.push(diff);\n }\n } catch (error) {\n if (error instanceof FileNotFoundError) {\n logger.warning(`File not found: ${file.source}`);\n } else if (error instanceof PermissionError) {\n logger.warning(`Permission denied: ${file.source}`);\n } else {\n throw error;\n }\n }\n }\n\n if (changedFiles.length === 0) {\n if (paths.length > 0) {\n logger.success('No differences found');\n } else {\n prompts.intro('tuck diff');\n console.log();\n logger.success('No differences found');\n console.log();\n }\n return;\n }\n\n prompts.intro('tuck diff');\n console.log();\n\n // Show stats/name-only if requested\n if (options.stat || options.nameOnly) {\n const label = options.nameOnly\n ? 'Changed files:'\n : `${changedFiles.length} file${changedFiles.length > 1 ? 's' : ''} changed:`;\n console.log(c.bold(label));\n console.log();\n\n for (const diff of changedFiles) {\n const status = diff.isDirectory ? c.dim('[dir]') : diff.isBinary ? c.dim('[bin]') : '';\n console.log(` ${c.yellow('~')} ${diff.source} ${status}`);\n }\n\n console.log();\n prompts.outro(`Found ${changedFiles.length} changed file(s)`);\n return;\n }\n\n // Show full diff for each file\n for (const diff of changedFiles) {\n console.log(formatUnifiedDiff(diff));\n console.log();\n }\n\n prompts.outro(`Found ${changedFiles.length} changed file(s)`);\n\n // Return exit code 1 if differences found and --exit-code is set\n if (options.exitCode) {\n process.exit(1);\n }\n};\n\nexport { runDiff, formatUnifiedDiff };\n\nexport const diffCommand = new Command('diff')\n .description('Show differences between system and repository')\n .argument('[paths...]', 'Specific files to diff')\n .option('--staged', 'Show staged git changes')\n .option('--stat', 'Show diffstat only')\n .option(\n '--category <category>',\n 'Filter by file category (shell, git, editors, terminal, ssh, misc)'\n )\n .option('--name-only', 'Show only changed file names')\n .option('--exit-code', 'Return exit code 1 if differences found')\n .action(async (paths: string[], options: DiffOptions) => {\n await runDiff(paths, options);\n });\n","import { Command } from 'commander';\nimport { spawn } from 'child_process';\nimport { prompts, logger, banner, colors as c } from '../ui/index.js';\nimport { getTuckDir, getConfigPath, collapsePath } from '../lib/paths.js';\nimport { loadConfig, saveConfig, resetConfig } from '../lib/config.js';\nimport { loadManifest } from '../lib/manifest.js';\nimport { addRemote, removeRemote, hasRemote } from '../lib/git.js';\nimport { NotInitializedError, ConfigError } from '../errors.js';\nimport type { TuckConfigOutput } from '../schemas/config.schema.js';\nimport { setupProvider } from '../lib/providerSetup.js';\nimport { describeProviderConfig, getProvider } from '../lib/providers/index.js';\n\n/**\n * Configuration key metadata for validation and help\n */\ninterface ConfigKeyInfo {\n path: string;\n type: 'boolean' | 'string' | 'enum';\n description: string;\n section: string;\n options?: string[]; // For enum types\n}\n\nconst CONFIG_KEYS: ConfigKeyInfo[] = [\n // Repository settings\n {\n path: 'repository.defaultBranch',\n type: 'string',\n description: 'Default git branch name',\n section: 'repository',\n },\n {\n path: 'repository.autoCommit',\n type: 'boolean',\n description: 'Auto-commit changes on sync',\n section: 'repository',\n },\n {\n path: 'repository.autoPush',\n type: 'boolean',\n description: 'Auto-push after commit',\n section: 'repository',\n },\n // File settings\n {\n path: 'files.strategy',\n type: 'enum',\n description: 'File copy strategy',\n section: 'files',\n options: ['copy', 'symlink'],\n },\n {\n path: 'files.backupOnRestore',\n type: 'boolean',\n description: 'Create backups before restore',\n section: 'files',\n },\n {\n path: 'files.backupDir',\n type: 'string',\n description: 'Backup directory path',\n section: 'files',\n },\n // UI settings\n { path: 'ui.colors', type: 'boolean', description: 'Enable colored output', section: 'ui' },\n { path: 'ui.emoji', type: 'boolean', description: 'Enable emoji in output', section: 'ui' },\n { path: 'ui.verbose', type: 'boolean', description: 'Enable verbose logging', section: 'ui' },\n // Hook settings\n {\n path: 'hooks.preSync',\n type: 'string',\n description: 'Command to run before sync',\n section: 'hooks',\n },\n {\n path: 'hooks.postSync',\n type: 'string',\n description: 'Command to run after sync',\n section: 'hooks',\n },\n {\n path: 'hooks.preRestore',\n type: 'string',\n description: 'Command to run before restore',\n section: 'hooks',\n },\n {\n path: 'hooks.postRestore',\n type: 'string',\n description: 'Command to run after restore',\n section: 'hooks',\n },\n // Template settings\n {\n path: 'templates.enabled',\n type: 'boolean',\n description: 'Enable template processing',\n section: 'templates',\n },\n // Encryption settings\n {\n path: 'encryption.enabled',\n type: 'boolean',\n description: 'Enable file encryption',\n section: 'encryption',\n },\n {\n path: 'encryption.gpgKey',\n type: 'string',\n description: 'GPG key for encryption',\n section: 'encryption',\n },\n];\n\nconst getKeyInfo = (path: string): ConfigKeyInfo | undefined => {\n return CONFIG_KEYS.find((k) => k.path === path);\n};\n\nconst formatConfigValue = (value: unknown): string => {\n if (value === undefined || value === null) return c.dim('(not set)');\n if (typeof value === 'boolean') return value ? c.green('true') : c.yellow('false');\n if (Array.isArray(value)) return value.length ? c.cyan(value.join(', ')) : c.dim('[]');\n if (typeof value === 'object') return c.dim(JSON.stringify(value));\n return c.white(String(value));\n};\n\nconst printConfig = (config: TuckConfigOutput): void => {\n console.log(JSON.stringify(config, null, 2));\n};\n\nconst getNestedValue = (obj: Record<string, unknown>, path: string): unknown => {\n const keys = path.split('.');\n let current: unknown = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined;\n }\n if (typeof current !== 'object') {\n return undefined;\n }\n current = (current as Record<string, unknown>)[key];\n }\n\n return current;\n};\n\nconst setNestedValue = (obj: Record<string, unknown>, path: string, value: unknown): void => {\n const keys = path.split('.');\n let current = obj;\n\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i];\n if (!(key in current) || typeof current[key] !== 'object') {\n current[key] = {};\n }\n current = current[key] as Record<string, unknown>;\n }\n\n current[keys[keys.length - 1]] = value;\n};\n\nconst parseValue = (value: string): unknown => {\n // Try to parse as JSON\n try {\n return JSON.parse(value);\n } catch {\n // Return as string if not valid JSON\n return value;\n }\n};\n\nconst runConfigGet = async (key: string): Promise<void> => {\n const tuckDir = getTuckDir();\n const config = await loadConfig(tuckDir);\n\n const value = getNestedValue(config as unknown as Record<string, unknown>, key);\n\n if (value === undefined) {\n logger.error(`Key not found: ${key}`);\n return;\n }\n\n if (typeof value === 'object') {\n console.log(JSON.stringify(value, null, 2));\n } else {\n console.log(value);\n }\n};\n\nconst runConfigSet = async (key: string, value: string): Promise<void> => {\n const tuckDir = getTuckDir();\n const config = await loadConfig(tuckDir);\n\n const parsedValue = parseValue(value);\n const configObj = config as unknown as Record<string, unknown>;\n\n setNestedValue(configObj, key, parsedValue);\n\n await saveConfig(config, tuckDir);\n logger.success(`Set ${key} = ${JSON.stringify(parsedValue)}`);\n};\n\nconst runConfigList = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n const config = await loadConfig(tuckDir);\n\n prompts.intro('tuck config');\n console.log();\n console.log(c.dim('Configuration file:'), collapsePath(getConfigPath(tuckDir)));\n console.log();\n\n printConfig(config);\n};\n\nconst runConfigEdit = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n const configPath = getConfigPath(tuckDir);\n\n const editor = process.env.EDITOR || process.env.VISUAL || 'vim';\n\n logger.info(`Opening ${collapsePath(configPath)} in ${editor}...`);\n\n return new Promise((resolve, reject) => {\n const child = spawn(editor, [configPath], {\n stdio: 'inherit',\n });\n\n child.on('exit', (code) => {\n if (code === 0) {\n logger.success('Configuration updated');\n resolve();\n } else {\n reject(new ConfigError(`Editor exited with code ${code}`));\n }\n });\n\n child.on('error', (err) => {\n reject(new ConfigError(`Failed to open editor: ${err.message}`));\n });\n });\n};\n\nconst runConfigReset = async (): Promise<void> => {\n const tuckDir = getTuckDir();\n\n const confirm = await prompts.confirm(\n 'Reset configuration to defaults? This cannot be undone.',\n false\n );\n\n if (!confirm) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n await resetConfig(tuckDir);\n logger.success('Configuration reset to defaults');\n};\n\n/**\n * Show configuration in a visually organized way\n */\nconst showConfigView = async (config: TuckConfigOutput): Promise<void> => {\n const configObj = config as unknown as Record<string, unknown>;\n\n // Show remote configuration first\n if (config.remote) {\n console.log(c.bold.cyan('~ Remote Provider'));\n console.log(c.dim('-'.repeat(40)));\n console.log(` ${describeProviderConfig(config.remote)}`);\n console.log();\n }\n\n const sections = [\n { key: 'repository', title: 'Repository Settings', icon: '*' },\n { key: 'files', title: 'File Management', icon: '>' },\n { key: 'ui', title: 'User Interface', icon: '#' },\n { key: 'hooks', title: 'Hooks', icon: '!' },\n { key: 'templates', title: 'Templates', icon: '%' },\n { key: 'encryption', title: 'Encryption', icon: '@' },\n ];\n\n for (const section of sections) {\n const sectionConfig = configObj[section.key];\n if (!sectionConfig || typeof sectionConfig !== 'object') continue;\n\n console.log(c.bold.cyan(`${section.icon} ${section.title}`));\n console.log(c.dim('-'.repeat(40)));\n\n for (const [key, value] of Object.entries(sectionConfig as Record<string, unknown>)) {\n const keyInfo = getKeyInfo(`${section.key}.${key}`);\n const displayValue = formatConfigValue(value);\n const description = keyInfo?.description || '';\n\n console.log(` ${c.white(key)}: ${displayValue}`);\n if (description) {\n console.log(c.dim(` ${description}`));\n }\n }\n console.log();\n }\n};\n\n/**\n * Run configuration wizard for guided setup\n */\nconst runConfigWizard = async (config: TuckConfigOutput, tuckDir: string): Promise<void> => {\n prompts.log.info(\"Let's configure tuck for your workflow\");\n console.log();\n\n // Repository behavior\n console.log(c.bold.cyan('* Repository Behavior'));\n const autoCommit = await prompts.confirm(\n 'Auto-commit changes when running sync?',\n config.repository.autoCommit ?? true\n );\n const autoPush = await prompts.confirm(\n 'Auto-push to remote after commit?',\n config.repository.autoPush ?? false\n );\n\n // File strategy\n console.log();\n console.log(c.bold.cyan('> File Strategy'));\n const rawStrategy = await prompts.select('How should tuck manage files?', [\n { value: 'copy', label: 'Copy files', hint: 'Safe, independent copies' },\n { value: 'symlink', label: 'Symlink files', hint: 'Real-time updates, single source of truth' },\n ]);\n const strategy: 'copy' | 'symlink' =\n rawStrategy === 'copy' || rawStrategy === 'symlink'\n ? rawStrategy\n : (config.files.strategy ?? 'copy');\n\n const backupOnRestore = await prompts.confirm(\n 'Create backups before restoring files?',\n config.files.backupOnRestore ?? true\n );\n\n // UI preferences\n console.log();\n console.log(c.bold.cyan('# User Interface'));\n const colors = await prompts.confirm('Enable colored output?', config.ui.colors ?? true);\n const emoji = await prompts.confirm('Enable emoji in output?', config.ui.emoji ?? true);\n const verbose = await prompts.confirm('Enable verbose logging?', config.ui.verbose ?? false);\n\n // Apply changes\n const updatedConfig: TuckConfigOutput = {\n ...config,\n repository: {\n ...config.repository,\n autoCommit,\n autoPush,\n },\n files: {\n ...config.files,\n strategy,\n backupOnRestore,\n },\n ui: {\n colors,\n emoji,\n verbose,\n },\n };\n\n await saveConfig(updatedConfig, tuckDir);\n\n console.log();\n prompts.log.success('Configuration updated!');\n prompts.note(\"Run 'tuck config' again to view or edit settings\", 'Tip');\n};\n\n/**\n * Interactive edit a single setting\n */\nconst editConfigInteractive = async (config: TuckConfigOutput, tuckDir: string): Promise<void> => {\n const configObj = config as unknown as Record<string, unknown>;\n\n // Create options for selection\n const options = CONFIG_KEYS.map((key) => {\n const currentValue = getNestedValue(configObj, key.path);\n return {\n value: key.path,\n label: key.path,\n hint: `${key.description} (current: ${formatConfigValue(currentValue)})`,\n };\n });\n\n const selectedKey = (await prompts.select('Select setting to edit:', options)) as string;\n const keyInfo = getKeyInfo(selectedKey);\n const currentValue = getNestedValue(configObj, selectedKey);\n\n if (!keyInfo) {\n logger.error(`Unknown key: ${selectedKey}`);\n return;\n }\n\n let newValue: unknown;\n\n switch (keyInfo.type) {\n case 'boolean': {\n const defaultValue = typeof currentValue === 'boolean' ? currentValue : false;\n newValue = await prompts.confirm(keyInfo.description, defaultValue);\n break;\n }\n case 'enum':\n newValue = await prompts.select(\n `Select value for ${selectedKey}:`,\n (keyInfo.options || []).map((opt) => ({ value: opt, label: opt }))\n );\n break;\n case 'string':\n newValue = await prompts.text(`Enter value for ${selectedKey}:`, {\n defaultValue: (currentValue as string) || '',\n placeholder: '(leave empty to clear)',\n });\n break;\n }\n\n setNestedValue(configObj, selectedKey, newValue);\n await saveConfig(config, tuckDir);\n\n prompts.log.success(`Updated ${selectedKey} = ${formatConfigValue(newValue)}`);\n};\n\n/**\n * Run interactive config mode\n */\nconst runInteractiveConfig = async (): Promise<void> => {\n banner();\n prompts.intro('tuck config');\n\n const tuckDir = getTuckDir();\n const config = await loadConfig(tuckDir);\n\n const action = (await prompts.select('What would you like to do?', [\n { value: 'view', label: 'View current configuration', hint: 'See all settings' },\n { value: 'edit', label: 'Edit a setting', hint: 'Modify a specific value' },\n { value: 'remote', label: 'Configure remote', hint: 'Set up GitHub, GitLab, or local mode' },\n { value: 'wizard', label: 'Run setup wizard', hint: 'Guided configuration' },\n { value: 'reset', label: 'Reset to defaults', hint: 'Restore default values' },\n { value: 'open', label: 'Open in editor', hint: `Edit with ${process.env.EDITOR || 'vim'}` },\n ])) as string;\n\n console.log();\n\n switch (action) {\n case 'view':\n await showConfigView(config);\n break;\n case 'edit':\n await editConfigInteractive(config, tuckDir);\n break;\n case 'remote':\n await runConfigRemote();\n return; // runConfigRemote has its own outro\n case 'wizard':\n await runConfigWizard(config, tuckDir);\n break;\n case 'reset':\n await runConfigReset();\n break;\n case 'open':\n await runConfigEdit();\n break;\n }\n\n prompts.outro('Done!');\n};\n\n/**\n * Run the remote provider configuration flow\n */\nconst runConfigRemote = async (): Promise<void> => {\n banner();\n prompts.intro('tuck config remote');\n\n const tuckDir = getTuckDir();\n const config = await loadConfig(tuckDir);\n\n // Show current configuration\n if (config.remote) {\n console.log();\n console.log(c.dim('Current remote configuration:'));\n console.log(` ${describeProviderConfig(config.remote)}`);\n console.log();\n }\n\n // Ask if they want to change\n const shouldChange = await prompts.confirm('Configure remote provider?', true);\n\n if (!shouldChange) {\n prompts.outro('No changes made');\n return;\n }\n\n // Run provider setup\n const result = await setupProvider();\n\n if (!result) {\n prompts.outro('Configuration cancelled');\n return;\n }\n\n // Update config with new remote settings\n const updatedConfig: TuckConfigOutput = {\n ...config,\n remote: result.config,\n };\n\n await saveConfig(updatedConfig, tuckDir);\n\n // If a remote URL was provided, update git remote\n if (result.remoteUrl) {\n try {\n // Check if origin already exists\n if (await hasRemote(tuckDir)) {\n // Remove existing remote\n await removeRemote(tuckDir, 'origin');\n }\n // Add new remote\n await addRemote(tuckDir, 'origin', result.remoteUrl);\n prompts.log.success('Git remote updated');\n } catch (error) {\n prompts.log.warning(\n `Could not update git remote: ${error instanceof Error ? error.message : String(error)}`\n );\n prompts.log.info(`Manually add remote: git remote add origin ${result.remoteUrl}`);\n }\n }\n\n // If switching to a provider that can create repos, offer to create one\n if (result.mode !== 'local' && result.mode !== 'custom' && !result.remoteUrl) {\n const shouldCreateRepo = await prompts.confirm(\n 'Would you like to create a repository now?',\n true\n );\n\n if (shouldCreateRepo) {\n const provider = getProvider(result.mode, result.config);\n\n const repoName = await prompts.text('Repository name:', {\n defaultValue: 'dotfiles',\n placeholder: 'dotfiles',\n validate: (value) => {\n if (!value) return 'Repository name is required';\n // Ensure name starts and ends with alphanumeric\n if (!/^[a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?$/.test(value)) {\n return 'Repository name must start and end with alphanumeric characters';\n }\n return undefined;\n },\n });\n\n const visibility = await prompts.select('Repository visibility:', [\n { value: 'private', label: 'Private (recommended)', hint: 'Only you can see it' },\n { value: 'public', label: 'Public', hint: 'Anyone can see it' },\n ]);\n\n try {\n const spinner = prompts.spinner();\n spinner.start('Creating repository...');\n\n const repo = await provider.createRepo({\n name: repoName,\n description: 'My dotfiles managed with tuck',\n isPrivate: visibility === 'private',\n });\n\n spinner.stop(`Repository created: ${repo.fullName}`);\n\n // Get preferred URL and add as remote\n const remoteUrl = await provider.getPreferredRepoUrl(repo);\n\n try {\n if (await hasRemote(tuckDir)) {\n await removeRemote(tuckDir, 'origin');\n }\n await addRemote(tuckDir, 'origin', remoteUrl);\n prompts.log.success('Remote configured');\n } catch (error) {\n prompts.log.warning(\n `Could not add remote: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n // Update config with repo name\n updatedConfig.remote = {\n ...updatedConfig.remote,\n repoName,\n };\n await saveConfig(updatedConfig, tuckDir);\n } catch (error) {\n prompts.log.error(\n `Failed to create repository: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n }\n\n console.log();\n prompts.log.success(`Remote configured: ${describeProviderConfig(result.config)}`);\n prompts.outro('Done!');\n};\n\nexport const configCommand = new Command('config')\n .description('Manage tuck configuration')\n .action(async () => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runInteractiveConfig();\n })\n .addCommand(\n new Command('get')\n .description('Get a config value')\n .argument('<key>', 'Config key (e.g., \"repository.autoCommit\")')\n .action(async (key: string) => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runConfigGet(key);\n })\n )\n .addCommand(\n new Command('set')\n .description('Set a config value')\n .argument('<key>', 'Config key')\n .argument('<value>', 'Value to set (JSON or string)')\n .action(async (key: string, value: string) => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runConfigSet(key, value);\n })\n )\n .addCommand(\n new Command('list').description('List all config').action(async () => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runConfigList();\n })\n )\n .addCommand(\n new Command('edit').description('Open config in editor').action(async () => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runConfigEdit();\n })\n )\n .addCommand(\n new Command('reset').description('Reset to defaults').action(async () => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runConfigReset();\n })\n )\n .addCommand(\n new Command('remote').description('Configure remote provider').action(async () => {\n const tuckDir = getTuckDir();\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n await runConfigRemote();\n })\n );\n","import { Command } from 'commander';\nimport { join } from 'path';\nimport { readFile, rm, chmod, stat } from 'fs/promises';\nimport { ensureDir, pathExists as fsPathExists } from 'fs-extra';\nimport { tmpdir } from 'os';\nimport { banner, prompts, logger, colors as c } from '../ui/index.js';\nimport { expandPath, pathExists, collapsePath, validateSafeSourcePath } from '../lib/paths.js';\nimport { cloneRepo } from '../lib/git.js';\nimport { isGhInstalled, findDotfilesRepo, ghCloneRepo, repoExists } from '../lib/github.js';\nimport { createPreApplySnapshot } from '../lib/timemachine.js';\nimport { smartMerge, isShellFile, generateMergePreview } from '../lib/merge.js';\nimport { copyFileOrDir } from '../lib/files.js';\nimport { CATEGORIES } from '../constants.js';\nimport type { TuckManifest } from '../types.js';\nimport { findPlaceholders } from '../lib/secrets/index.js';\n\n/**\n * Fix permissions for SSH/GPG files after apply\n */\nconst fixSecurePermissions = async (path: string): Promise<void> => {\n const collapsedPath = collapsePath(path);\n\n // Only fix permissions for SSH and GPG files\n if (!collapsedPath.includes('.ssh/') && !collapsedPath.includes('.gnupg/')) {\n return;\n }\n\n try {\n const stats = await stat(path);\n\n if (stats.isDirectory()) {\n await chmod(path, 0o700);\n } else {\n await chmod(path, 0o600);\n }\n } catch {\n // Ignore permission errors (might be on Windows)\n }\n};\n\nexport interface ApplyOptions {\n merge?: boolean;\n replace?: boolean;\n dryRun?: boolean;\n force?: boolean;\n yes?: boolean;\n}\n\ninterface ApplyFile {\n source: string;\n destination: string;\n category: string;\n repoPath: string;\n}\n\ninterface ApplyResult {\n appliedCount: number;\n filesWithPlaceholders: Array<{\n path: string;\n placeholders: string[];\n }>;\n}\n\n/**\n * Resolve a source (username or repo URL) to a full repository identifier\n */\nconst resolveSource = async (source: string): Promise<{ repoId: string; isUrl: boolean }> => {\n // Check if it's a full URL\n if (source.includes('://') || source.startsWith('git@')) {\n return { repoId: source, isUrl: true };\n }\n\n // Check if it's a GitHub repo identifier (user/repo)\n if (source.includes('/')) {\n return { repoId: source, isUrl: false };\n }\n\n // Assume it's a username, try to find their dotfiles repo\n logger.info(`Looking for dotfiles repository for ${source}...`);\n\n if (await isGhInstalled()) {\n const dotfilesRepo = await findDotfilesRepo(source);\n if (dotfilesRepo) {\n logger.success(`Found repository: ${dotfilesRepo}`);\n return { repoId: dotfilesRepo, isUrl: false };\n }\n }\n\n // Try common repo names\n const commonNames = ['dotfiles', 'tuck', '.dotfiles'];\n for (const name of commonNames) {\n const repoId = `${source}/${name}`;\n if (await repoExists(repoId)) {\n logger.success(`Found repository: ${repoId}`);\n return { repoId, isUrl: false };\n }\n }\n\n throw new Error(\n `Could not find a dotfiles repository for \"${source}\". ` +\n 'Try specifying the full repository name (e.g., username/dotfiles)'\n );\n};\n\n/**\n * Clone the source repository to a temporary directory\n */\nconst cloneSource = async (repoId: string, isUrl: boolean): Promise<string> => {\n const tempDir = join(tmpdir(), `tuck-apply-${Date.now()}`);\n await ensureDir(tempDir);\n\n if (isUrl) {\n await cloneRepo(repoId, tempDir);\n } else {\n // Use gh CLI to clone if available, otherwise construct URL\n if (await isGhInstalled()) {\n await ghCloneRepo(repoId, tempDir);\n } else {\n const url = `https://github.com/${repoId}.git`;\n await cloneRepo(url, tempDir);\n }\n }\n\n return tempDir;\n};\n\n/**\n * Read the manifest from a cloned repository\n */\nconst readClonedManifest = async (repoDir: string): Promise<TuckManifest | null> => {\n const manifestPath = join(repoDir, '.tuckmanifest.json');\n\n if (!(await fsPathExists(manifestPath))) {\n return null;\n }\n\n try {\n const content = await readFile(manifestPath, 'utf-8');\n return JSON.parse(content) as TuckManifest;\n } catch {\n return null;\n }\n};\n\n/**\n * Prepare the list of files to apply\n */\nconst prepareFilesToApply = async (\n repoDir: string,\n manifest: TuckManifest\n): Promise<ApplyFile[]> => {\n const files: ApplyFile[] = [];\n\n for (const [_id, file] of Object.entries(manifest.files)) {\n const repoFilePath = join(repoDir, file.destination);\n\n if (await fsPathExists(repoFilePath)) {\n // Validate that the source path is safe (within home directory)\n // This prevents malicious manifests from writing to arbitrary locations\n try {\n validateSafeSourcePath(file.source);\n } catch (error) {\n logger.warning(`Skipping unsafe path from manifest: ${file.source}`);\n continue;\n }\n\n files.push({\n source: file.source,\n destination: expandPath(file.source),\n category: file.category,\n repoPath: repoFilePath,\n });\n }\n }\n\n return files;\n};\n\n/**\n * Apply files with merge strategy\n */\nconst applyWithMerge = async (files: ApplyFile[], dryRun: boolean): Promise<ApplyResult> => {\n const result: ApplyResult = {\n appliedCount: 0,\n filesWithPlaceholders: [],\n };\n\n for (const file of files) {\n const fileContent = await readFile(file.repoPath, 'utf-8');\n\n // Check for placeholders that need secret values\n const placeholders = findPlaceholders(fileContent);\n if (placeholders.length > 0) {\n result.filesWithPlaceholders.push({\n path: collapsePath(file.destination),\n placeholders,\n });\n }\n\n if (isShellFile(file.source) && (await pathExists(file.destination))) {\n // Use smart merge for shell files\n const mergeResult = await smartMerge(file.destination, fileContent);\n\n if (dryRun) {\n logger.file(\n 'merge',\n `${collapsePath(file.destination)} (${mergeResult.preservedBlocks} blocks preserved)`\n );\n } else {\n const { writeFile } = await import('fs/promises');\n const { ensureDir } = await import('fs-extra');\n const { dirname } = await import('path');\n\n await ensureDir(dirname(file.destination));\n await writeFile(file.destination, mergeResult.content, 'utf-8');\n logger.file('merge', collapsePath(file.destination));\n }\n } else {\n // Copy non-shell files directly\n if (dryRun) {\n if (await pathExists(file.destination)) {\n logger.file('modify', collapsePath(file.destination));\n } else {\n logger.file('add', collapsePath(file.destination));\n }\n } else {\n const fileExists = await pathExists(file.destination);\n await copyFileOrDir(file.repoPath, file.destination, { overwrite: true });\n await fixSecurePermissions(file.destination);\n logger.file(fileExists ? 'modify' : 'add', collapsePath(file.destination));\n }\n }\n\n result.appliedCount++;\n }\n\n return result;\n};\n\n/**\n * Apply files with replace strategy\n */\nconst applyWithReplace = async (files: ApplyFile[], dryRun: boolean): Promise<ApplyResult> => {\n const result: ApplyResult = {\n appliedCount: 0,\n filesWithPlaceholders: [],\n };\n\n for (const file of files) {\n // Check for placeholders that need secret values\n const fileContent = await readFile(file.repoPath, 'utf-8');\n const placeholders = findPlaceholders(fileContent);\n if (placeholders.length > 0) {\n result.filesWithPlaceholders.push({\n path: collapsePath(file.destination),\n placeholders,\n });\n }\n\n if (dryRun) {\n if (await pathExists(file.destination)) {\n logger.file('modify', `${collapsePath(file.destination)} (replace)`);\n } else {\n logger.file('add', collapsePath(file.destination));\n }\n } else {\n const fileExists = await pathExists(file.destination);\n await copyFileOrDir(file.repoPath, file.destination, { overwrite: true });\n await fixSecurePermissions(file.destination);\n logger.file(fileExists ? 'modify' : 'add', collapsePath(file.destination));\n }\n\n result.appliedCount++;\n }\n\n return result;\n};\n\n/**\n * Display warnings for files with unresolved placeholders\n */\nconst displayPlaceholderWarnings = (\n filesWithPlaceholders: ApplyResult['filesWithPlaceholders']\n): void => {\n if (filesWithPlaceholders.length === 0) return;\n\n console.log();\n console.log(c.yellow('⚠ Warning: Some files contain unresolved placeholders:'));\n console.log();\n\n for (const { path, placeholders } of filesWithPlaceholders) {\n console.log(c.dim(` ${path}:`));\n\n const maxToShow = 5;\n if (placeholders.length <= maxToShow) {\n // For small numbers, show all placeholders\n for (const placeholder of placeholders) {\n console.log(c.yellow(` {{${placeholder}}}`));\n }\n } else {\n // For larger numbers, show a sampling: first 3 and last 2\n const firstCount = 3;\n const lastCount = 2;\n const firstPlaceholders = placeholders.slice(0, firstCount);\n const lastPlaceholders = placeholders.slice(-lastCount);\n\n for (const placeholder of firstPlaceholders) {\n console.log(c.yellow(` {{${placeholder}}}`));\n }\n\n // Indicate that some placeholders are omitted in the middle\n console.log(c.dim(' ...'));\n\n for (const placeholder of lastPlaceholders) {\n console.log(c.yellow(` {{${placeholder}}}`));\n }\n\n const shownCount = firstPlaceholders.length + lastPlaceholders.length;\n const hiddenCount = placeholders.length - shownCount;\n if (hiddenCount > 0) {\n console.log(c.dim(` ... and ${hiddenCount} more not shown`));\n }\n }\n }\n\n console.log();\n console.log(c.dim(' These placeholders need to be replaced with actual values.'));\n console.log(c.dim(' Use `tuck secrets set <NAME> <value>` to configure secrets,'));\n console.log(c.dim(' then re-apply to populate them.'));\n};\n\n/**\n * Run interactive apply flow\n */\nconst runInteractiveApply = async (source: string, options: ApplyOptions): Promise<void> => {\n banner();\n prompts.intro('tuck apply');\n\n // Resolve the source\n let repoId: string;\n let isUrl: boolean;\n\n try {\n const resolved = await resolveSource(source);\n repoId = resolved.repoId;\n isUrl = resolved.isUrl;\n } catch (error) {\n prompts.log.error(error instanceof Error ? error.message : String(error));\n return;\n }\n\n // Clone the repository\n let repoDir: string;\n try {\n const spinner = prompts.spinner();\n spinner.start('Cloning repository...');\n repoDir = await cloneSource(repoId, isUrl);\n spinner.stop('Repository cloned');\n } catch (error) {\n prompts.log.error(`Failed to clone: ${error instanceof Error ? error.message : String(error)}`);\n return;\n }\n\n try {\n // Read the manifest\n const manifest = await readClonedManifest(repoDir);\n\n if (!manifest) {\n prompts.log.error('No tuck manifest found in repository');\n prompts.note(\n 'This repository may not be managed by tuck.\\nLook for a .tuckmanifest.json file.',\n 'Tip'\n );\n return;\n }\n\n // Prepare files to apply\n const files = await prepareFilesToApply(repoDir, manifest);\n\n if (files.length === 0) {\n prompts.log.warning('No files to apply');\n return;\n }\n\n // Show what will be applied\n prompts.log.info(`Found ${files.length} file(s) to apply:`);\n console.log();\n\n // Group by category\n const byCategory: Record<string, ApplyFile[]> = {};\n for (const file of files) {\n if (!byCategory[file.category]) {\n byCategory[file.category] = [];\n }\n byCategory[file.category].push(file);\n }\n\n for (const [category, categoryFiles] of Object.entries(byCategory)) {\n const categoryConfig = CATEGORIES[category] || { icon: '📄' };\n console.log(c.bold(` ${categoryConfig.icon} ${category}`));\n for (const file of categoryFiles) {\n const exists = await pathExists(file.destination);\n const status = exists ? c.yellow('(will update)') : c.green('(new)');\n console.log(c.dim(` ${collapsePath(file.destination)} ${status}`));\n }\n }\n console.log();\n\n // Ask for merge strategy\n let strategy: 'merge' | 'replace';\n\n if (options.merge) {\n strategy = 'merge';\n } else if (options.replace) {\n strategy = 'replace';\n } else {\n strategy = await prompts.select('How should conflicts be handled?', [\n {\n value: 'merge',\n label: 'Merge (recommended)',\n hint: 'Preserve local customizations marked with # local or # tuck:preserve',\n },\n {\n value: 'replace',\n label: 'Replace',\n hint: 'Overwrite all files completely',\n },\n ]);\n }\n\n // Show merge preview for shell files if using merge strategy\n if (strategy === 'merge') {\n const shellFiles = files.filter((f) => isShellFile(f.source));\n if (shellFiles.length > 0) {\n console.log();\n for (const file of shellFiles.slice(0, 3)) {\n if (await pathExists(file.destination)) {\n const fileContent = await readFile(file.repoPath, 'utf-8');\n const preview = await generateMergePreview(file.destination, fileContent);\n prompts.note(preview, collapsePath(file.destination));\n }\n }\n if (shellFiles.length > 3) {\n prompts.log.info(`... and ${shellFiles.length - 3} more shell files`);\n }\n }\n }\n\n // Confirm\n if (!options.yes && !options.force) {\n console.log();\n const confirmed = await prompts.confirm(\n `Apply ${files.length} files using ${strategy} strategy?`,\n true\n );\n\n if (!confirmed) {\n prompts.cancel('Apply cancelled');\n return;\n }\n }\n\n // Create Time Machine backup before applying\n // Note: We need to properly await async checks - Array.filter doesn't await promises\n const existingPaths = [];\n for (const file of files) {\n if (await pathExists(file.destination)) {\n existingPaths.push(file.destination);\n }\n }\n\n if (existingPaths.length > 0 && !options.dryRun) {\n const spinner = prompts.spinner();\n spinner.start('Creating backup snapshot...');\n const snapshot = await createPreApplySnapshot(existingPaths, repoId);\n spinner.stop(`Backup created: ${snapshot.id}`);\n console.log();\n }\n\n // Apply files\n if (options.dryRun) {\n prompts.log.info('Dry run - no changes will be made:');\n } else {\n prompts.log.info('Applying files...');\n }\n console.log();\n\n let applyResult: ApplyResult;\n if (strategy === 'merge') {\n applyResult = await applyWithMerge(files, options.dryRun || false);\n } else {\n applyResult = await applyWithReplace(files, options.dryRun || false);\n }\n\n console.log();\n\n if (options.dryRun) {\n prompts.log.info(`Would apply ${applyResult.appliedCount} files`);\n } else {\n prompts.log.success(`Applied ${applyResult.appliedCount} files`);\n }\n\n // Show placeholder warnings\n displayPlaceholderWarnings(applyResult.filesWithPlaceholders);\n\n if (!options.dryRun) {\n console.log();\n prompts.note(\n 'To undo this apply, run:\\n tuck restore --latest\\n\\nTo see all backups:\\n tuck restore --list',\n 'Undo'\n );\n }\n\n prompts.outro('Done!');\n } finally {\n // Clean up temp directory\n try {\n await rm(repoDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n};\n\n/**\n * Run non-interactive apply\n */\nconst runApply = async (source: string, options: ApplyOptions): Promise<void> => {\n // Resolve the source\n const { repoId, isUrl } = await resolveSource(source);\n\n // Clone the repository\n logger.info('Cloning repository...');\n const repoDir = await cloneSource(repoId, isUrl);\n\n try {\n // Read the manifest\n const manifest = await readClonedManifest(repoDir);\n\n if (!manifest) {\n throw new Error('No tuck manifest found in repository');\n }\n\n // Prepare files to apply\n const files = await prepareFilesToApply(repoDir, manifest);\n\n if (files.length === 0) {\n logger.warning('No files to apply');\n return;\n }\n\n // Determine strategy\n const strategy = options.replace ? 'replace' : 'merge';\n\n // Create backup if not dry run\n if (!options.dryRun) {\n const existingPaths = [];\n for (const file of files) {\n if (await pathExists(file.destination)) {\n existingPaths.push(file.destination);\n }\n }\n\n if (existingPaths.length > 0) {\n logger.info('Creating backup snapshot...');\n const snapshot = await createPreApplySnapshot(existingPaths, repoId);\n logger.success(`Backup created: ${snapshot.id}`);\n }\n }\n\n // Apply files\n if (options.dryRun) {\n logger.heading('Dry run - would apply:');\n } else {\n logger.heading('Applying:');\n }\n\n let applyResult: ApplyResult;\n if (strategy === 'merge') {\n applyResult = await applyWithMerge(files, options.dryRun || false);\n } else {\n applyResult = await applyWithReplace(files, options.dryRun || false);\n }\n\n logger.blank();\n\n if (options.dryRun) {\n logger.info(`Would apply ${applyResult.appliedCount} files`);\n } else {\n logger.success(`Applied ${applyResult.appliedCount} files`);\n }\n\n // Show placeholder warnings\n displayPlaceholderWarnings(applyResult.filesWithPlaceholders);\n\n if (!options.dryRun) {\n logger.info('To undo: tuck restore --latest');\n }\n } finally {\n // Clean up temp directory\n try {\n await rm(repoDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n};\n\nexport const applyCommand = new Command('apply')\n .description('Apply dotfiles from a repository to this machine')\n .argument('<source>', 'GitHub username, user/repo, or full repository URL')\n .option('-m, --merge', 'Merge with existing files (preserve local customizations)')\n .option('-r, --replace', 'Replace existing files completely')\n .option('--dry-run', 'Show what would be applied without making changes')\n .option('-f, --force', 'Apply without confirmation prompts')\n .option('-y, --yes', 'Assume yes to all prompts')\n .action(async (source: string, options: ApplyOptions) => {\n // Determine if we should run interactive mode\n const isInteractive = !options.force && !options.yes && process.stdout.isTTY;\n\n if (isInteractive) {\n await runInteractiveApply(source, options);\n } else {\n await runApply(source, options);\n }\n });\n","import { join, dirname } from 'path';\nimport { readdir, readFile, writeFile, rm, stat } from 'fs/promises';\nimport { copy, ensureDir, pathExists } from 'fs-extra';\nimport { homedir } from 'os';\nimport { expandPath, collapsePath, pathExists as checkPathExists } from './paths.js';\nimport { BackupError } from '../errors.js';\n\nconst TIMEMACHINE_DIR = join(homedir(), '.tuck', 'backups');\n\nexport interface SnapshotMetadata {\n id: string;\n timestamp: string;\n reason: string;\n files: SnapshotFile[];\n machine: string;\n profile?: string;\n}\n\nexport interface SnapshotFile {\n originalPath: string;\n backupPath: string;\n existed: boolean;\n}\n\nexport interface Snapshot {\n id: string;\n path: string;\n timestamp: Date;\n reason: string;\n files: SnapshotFile[];\n machine: string;\n profile?: string;\n}\n\n/**\n * Generate a unique snapshot ID (YYYY-MM-DD-HHMMSS)\n */\nconst generateSnapshotId = (): string => {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n const hours = String(now.getHours()).padStart(2, '0');\n const minutes = String(now.getMinutes()).padStart(2, '0');\n const seconds = String(now.getSeconds()).padStart(2, '0');\n return `${year}-${month}-${day}-${hours}${minutes}${seconds}`;\n};\n\n/**\n * Get the path to a snapshot directory\n */\nconst getSnapshotPath = (snapshotId: string): string => {\n return join(TIMEMACHINE_DIR, snapshotId);\n};\n\n/**\n * Convert original path to a safe backup path, preserving directory structure\n * to prevent filename collisions. The path is relative to the backup files directory.\n * e.g., ~/.zshrc -> .zshrc\n * e.g., ~/.config/nvim -> .config/nvim\n * e.g., ~/.foo.bar -> .foo.bar (distinct from ~/.foo-bar -> .foo-bar)\n */\nconst toBackupPath = (originalPath: string): string => {\n const collapsed = collapsePath(originalPath);\n // Remove ~/ prefix to get a path relative to home directory\n // This preserves the full directory structure, preventing collisions\n return collapsed.replace(/^~\\//, '');\n};\n\n/**\n * Create a Time Machine snapshot of multiple files\n * This is the main entry point for creating backups before apply operations\n */\nexport const createSnapshot = async (\n filePaths: string[],\n reason: string,\n profile?: string\n): Promise<Snapshot> => {\n const snapshotId = generateSnapshotId();\n const snapshotPath = getSnapshotPath(snapshotId);\n\n await ensureDir(snapshotPath);\n\n const files: SnapshotFile[] = [];\n const machine = (await import('os')).hostname();\n\n for (const filePath of filePaths) {\n const expandedPath = expandPath(filePath);\n const backupRelativePath = toBackupPath(expandedPath);\n const backupPath = join(snapshotPath, 'files', backupRelativePath);\n\n const existed = await checkPathExists(expandedPath);\n\n if (existed) {\n await ensureDir(dirname(backupPath));\n await copy(expandedPath, backupPath, { overwrite: true, preserveTimestamps: true });\n }\n\n files.push({\n originalPath: expandedPath,\n backupPath,\n existed,\n });\n }\n\n // Save metadata\n const metadata: SnapshotMetadata = {\n id: snapshotId,\n timestamp: new Date().toISOString(),\n reason,\n files,\n machine,\n profile,\n };\n\n await writeFile(\n join(snapshotPath, 'metadata.json'),\n JSON.stringify(metadata, null, 2),\n 'utf-8'\n );\n\n return {\n id: snapshotId,\n path: snapshotPath,\n timestamp: new Date(metadata.timestamp),\n reason,\n files,\n machine,\n profile,\n };\n};\n\n/**\n * Create a snapshot of the user's current dotfiles before applying new ones\n */\nexport const createPreApplySnapshot = async (\n targetPaths: string[],\n sourceRepo?: string\n): Promise<Snapshot> => {\n const reason = sourceRepo\n ? `Pre-apply backup before applying from ${sourceRepo}`\n : 'Pre-apply backup';\n\n return createSnapshot(targetPaths, reason);\n};\n\n/**\n * List all available snapshots\n */\nexport const listSnapshots = async (): Promise<Snapshot[]> => {\n if (!(await pathExists(TIMEMACHINE_DIR))) {\n return [];\n }\n\n const entries = await readdir(TIMEMACHINE_DIR, { withFileTypes: true });\n const snapshots: Snapshot[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const snapshotPath = join(TIMEMACHINE_DIR, entry.name);\n const metadataPath = join(snapshotPath, 'metadata.json');\n\n if (!(await pathExists(metadataPath))) continue;\n\n try {\n const content = await readFile(metadataPath, 'utf-8');\n const metadata: SnapshotMetadata = JSON.parse(content);\n\n snapshots.push({\n id: metadata.id,\n path: snapshotPath,\n timestamp: new Date(metadata.timestamp),\n reason: metadata.reason,\n files: metadata.files,\n machine: metadata.machine,\n profile: metadata.profile,\n });\n } catch {\n // Skip invalid snapshots\n }\n }\n\n // Sort by timestamp, newest first\n return snapshots.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n};\n\n/**\n * Get a specific snapshot by ID\n */\nexport const getSnapshot = async (snapshotId: string): Promise<Snapshot | null> => {\n const snapshotPath = getSnapshotPath(snapshotId);\n\n if (!(await pathExists(snapshotPath))) {\n return null;\n }\n\n const metadataPath = join(snapshotPath, 'metadata.json');\n\n if (!(await pathExists(metadataPath))) {\n return null;\n }\n\n try {\n const content = await readFile(metadataPath, 'utf-8');\n const metadata: SnapshotMetadata = JSON.parse(content);\n\n return {\n id: metadata.id,\n path: snapshotPath,\n timestamp: new Date(metadata.timestamp),\n reason: metadata.reason,\n files: metadata.files,\n machine: metadata.machine,\n profile: metadata.profile,\n };\n } catch {\n return null;\n }\n};\n\n/**\n * Get the latest snapshot\n */\nexport const getLatestSnapshot = async (): Promise<Snapshot | null> => {\n const snapshots = await listSnapshots();\n return snapshots.length > 0 ? snapshots[0] : null;\n};\n\n/**\n * Restore all files from a snapshot\n */\nexport const restoreSnapshot = async (snapshotId: string): Promise<string[]> => {\n const snapshot = await getSnapshot(snapshotId);\n\n if (!snapshot) {\n throw new BackupError(`Snapshot not found: ${snapshotId}`, [\n 'Run `tuck restore --list` to see available snapshots',\n ]);\n }\n\n const restoredFiles: string[] = [];\n\n for (const file of snapshot.files) {\n if (!file.existed) {\n // File didn't exist before, delete it if it exists now\n if (await checkPathExists(file.originalPath)) {\n await rm(file.originalPath, { recursive: true });\n }\n continue;\n }\n\n // Restore the backup\n if (await pathExists(file.backupPath)) {\n await ensureDir(dirname(file.originalPath));\n await copy(file.backupPath, file.originalPath, { overwrite: true, preserveTimestamps: true });\n restoredFiles.push(file.originalPath);\n }\n }\n\n return restoredFiles;\n};\n\n/**\n * Restore a single file from a snapshot\n */\nexport const restoreFileFromSnapshot = async (\n snapshotId: string,\n filePath: string\n): Promise<boolean> => {\n const snapshot = await getSnapshot(snapshotId);\n\n if (!snapshot) {\n throw new BackupError(`Snapshot not found: ${snapshotId}`);\n }\n\n const expandedPath = expandPath(filePath);\n const file = snapshot.files.find((f) => f.originalPath === expandedPath);\n\n if (!file) {\n throw new BackupError(`File not found in snapshot: ${filePath}`, [\n 'This file was not included in the snapshot',\n ]);\n }\n\n if (!file.existed) {\n // File didn't exist before, delete it if it exists now\n if (await checkPathExists(file.originalPath)) {\n await rm(file.originalPath, { recursive: true });\n }\n return true;\n }\n\n if (!(await pathExists(file.backupPath))) {\n throw new BackupError(`Backup file is missing: ${file.backupPath}`);\n }\n\n await ensureDir(dirname(file.originalPath));\n await copy(file.backupPath, file.originalPath, { overwrite: true, preserveTimestamps: true });\n return true;\n};\n\n/**\n * Delete a snapshot\n */\nexport const deleteSnapshot = async (snapshotId: string): Promise<void> => {\n const snapshotPath = getSnapshotPath(snapshotId);\n\n if (await pathExists(snapshotPath)) {\n await rm(snapshotPath, { recursive: true });\n }\n};\n\n/**\n * Clean up old snapshots, keeping only the specified number\n */\nexport const cleanOldSnapshots = async (keepCount: number): Promise<number> => {\n const snapshots = await listSnapshots();\n\n if (snapshots.length <= keepCount) {\n return 0;\n }\n\n const toDelete = snapshots.slice(keepCount);\n let deletedCount = 0;\n\n for (const snapshot of toDelete) {\n await deleteSnapshot(snapshot.id);\n deletedCount++;\n }\n\n return deletedCount;\n};\n\n/**\n * Get the total size of all snapshots in bytes\n */\nexport const getSnapshotsSize = async (): Promise<number> => {\n if (!(await pathExists(TIMEMACHINE_DIR))) {\n return 0;\n }\n\n let totalSize = 0;\n\n const calculateDirSize = async (dirPath: string): Promise<number> => {\n let size = 0;\n const entries = await readdir(dirPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = join(dirPath, entry.name);\n if (entry.isDirectory()) {\n size += await calculateDirSize(entryPath);\n } else {\n const stats = await stat(entryPath);\n size += stats.size;\n }\n }\n\n return size;\n };\n\n totalSize = await calculateDirSize(TIMEMACHINE_DIR);\n return totalSize;\n};\n\n/**\n * Format bytes to human readable string\n */\nexport const formatSnapshotSize = (bytes: number): string => {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n};\n\n/**\n * Format a snapshot ID to a human-readable date string\n */\nexport const formatSnapshotDate = (snapshotId: string): string => {\n // Parse YYYY-MM-DD-HHMMSS format\n const match = snapshotId.match(/^(\\d{4})-(\\d{2})-(\\d{2})-(\\d{2})(\\d{2})(\\d{2})$/);\n if (!match) return snapshotId;\n\n const [, year, month, day, hours, minutes, seconds] = match;\n const date = new Date(\n parseInt(year),\n parseInt(month) - 1,\n parseInt(day),\n parseInt(hours),\n parseInt(minutes),\n parseInt(seconds)\n );\n\n return date.toLocaleString();\n};\n","import { readFile } from 'fs/promises';\nimport { expandPath, pathExists } from './paths.js';\n\n/**\n * Markers that indicate content should be preserved during merge\n */\nconst PRESERVE_MARKERS = [\n '# local',\n '# LOCAL',\n '# machine-specific',\n '# MACHINE-SPECIFIC',\n '# machine specific',\n '# do not sync',\n '# DO NOT SYNC',\n '# keep',\n '# KEEP',\n '# private',\n '# PRIVATE',\n '# tuck:preserve',\n '# tuck:keep',\n '# tuck:local',\n];\n\n/**\n * Shell file patterns that are known to be shell configuration\n */\nconst SHELL_FILE_PATTERNS = [\n '.zshrc',\n '.bashrc',\n '.bash_profile',\n '.profile',\n '.zprofile',\n '.zshenv',\n '.bash_aliases',\n '.aliases',\n '.functions',\n];\n\nexport interface MergeBlock {\n type: 'preserved' | 'incoming' | 'local';\n content: string;\n marker?: string;\n lineStart: number;\n lineEnd: number;\n}\n\nexport interface MergeResult {\n content: string;\n preservedBlocks: number;\n incomingBlocks: number;\n conflicts: MergeConflict[];\n}\n\nexport interface MergeConflict {\n type: 'duplicate_export' | 'duplicate_alias' | 'duplicate_function';\n name: string;\n localLine: number;\n incomingLine: number;\n}\n\nexport interface ParsedExport {\n name: string;\n value: string;\n line: number;\n fullLine: string;\n}\n\nexport interface ParsedAlias {\n name: string;\n value: string;\n line: number;\n fullLine: string;\n}\n\nexport interface ParsedFunction {\n name: string;\n content: string;\n lineStart: number;\n lineEnd: number;\n}\n\n/**\n * Check if a file is a shell configuration file\n */\nexport const isShellFile = (filePath: string): boolean => {\n const fileName = filePath.split('/').pop() || '';\n return SHELL_FILE_PATTERNS.some(\n (pattern) => fileName === pattern || fileName.endsWith(pattern)\n );\n};\n\n/**\n * Parse export statements from shell content\n * Handles: export FOO=bar, export FOO=\"bar\", FOO=bar\n */\nexport const parseExports = (content: string): ParsedExport[] => {\n const exports: ParsedExport[] = [];\n const lines = content.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n // Skip comments and empty lines\n if (line.startsWith('#') || !line) continue;\n\n // Match export statements\n const exportMatch = line.match(/^(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);\n if (exportMatch) {\n exports.push({\n name: exportMatch[1],\n value: exportMatch[2],\n line: i + 1,\n fullLine: lines[i],\n });\n }\n }\n\n return exports;\n};\n\n/**\n * Parse alias definitions from shell content\n * Handles: alias foo='bar', alias foo=\"bar\"\n */\nexport const parseAliases = (content: string): ParsedAlias[] => {\n const aliases: ParsedAlias[] = [];\n const lines = content.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n // Skip comments and empty lines\n if (line.startsWith('#') || !line) continue;\n\n // Match alias statements\n const aliasMatch = line.match(/^alias\\s+([a-zA-Z_][a-zA-Z0-9_-]*)=(['\"]?)(.+?)\\2\\s*$/);\n if (aliasMatch) {\n aliases.push({\n name: aliasMatch[1],\n value: aliasMatch[3],\n line: i + 1,\n fullLine: lines[i],\n });\n }\n }\n\n return aliases;\n};\n\n/**\n * Find blocks that should be preserved during merge\n * A preserved block starts with a preserve marker and ends at:\n * - The next non-indented non-comment line\n * - The end of file\n * - Another preserve marker\n */\nexport const findPreservedBlocks = (content: string): MergeBlock[] => {\n const blocks: MergeBlock[] = [];\n const lines = content.split('\\n');\n let currentBlock: MergeBlock | null = null;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmedLine = line.trim();\n\n // Check if this line has a preserve marker\n const marker = PRESERVE_MARKERS.find((m) => trimmedLine.includes(m));\n\n if (marker) {\n // Save previous block if exists\n if (currentBlock) {\n currentBlock.lineEnd = i;\n currentBlock.content = lines.slice(currentBlock.lineStart - 1, i).join('\\n');\n blocks.push(currentBlock);\n }\n\n // Start new preserved block\n currentBlock = {\n type: 'preserved',\n content: '',\n marker,\n lineStart: i + 1,\n lineEnd: i + 1,\n };\n } else if (currentBlock) {\n // Check if we should end the current block\n // End if: empty line followed by non-indented content, or end of file\n const isEndOfBlock =\n (trimmedLine === '' && i + 1 < lines.length && !lines[i + 1].startsWith(' ') && !lines[i + 1].startsWith('\\t') && lines[i + 1].trim() !== '' && !lines[i + 1].trim().startsWith('#')) ||\n i === lines.length - 1;\n\n if (isEndOfBlock) {\n currentBlock.lineEnd = i + 1;\n currentBlock.content = lines.slice(currentBlock.lineStart - 1, i + 1).join('\\n');\n blocks.push(currentBlock);\n currentBlock = null;\n }\n }\n }\n\n // Handle block that extends to end of file\n if (currentBlock) {\n currentBlock.lineEnd = lines.length;\n currentBlock.content = lines.slice(currentBlock.lineStart - 1).join('\\n');\n blocks.push(currentBlock);\n }\n\n return blocks;\n};\n\n/**\n * Extract PATH modifications from content\n */\nexport const extractPathModifications = (content: string): string[] => {\n const paths: string[] = [];\n const lines = content.split('\\n');\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.startsWith('#')) continue;\n\n // Match PATH exports\n if (trimmed.includes('PATH') && (trimmed.includes('export') || trimmed.includes('='))) {\n paths.push(line);\n }\n }\n\n return paths;\n};\n\n/**\n * Smart merge of shell configuration files\n * Preserves local customizations while applying incoming changes\n */\nexport const smartMerge = async (\n localPath: string,\n incomingContent: string\n): Promise<MergeResult> => {\n const expandedPath = expandPath(localPath);\n\n // If local file doesn't exist, just return incoming content\n if (!(await pathExists(expandedPath))) {\n return {\n content: incomingContent,\n preservedBlocks: 0,\n incomingBlocks: 1,\n conflicts: [],\n };\n }\n\n const localContent = await readFile(expandedPath, 'utf-8');\n\n // Find blocks to preserve from local content\n const preservedBlocks = findPreservedBlocks(localContent);\n\n // Parse exports and aliases from both files\n const localExports = parseExports(localContent);\n const incomingExports = parseExports(incomingContent);\n const localAliases = parseAliases(localContent);\n const incomingAliases = parseAliases(incomingContent);\n\n // Find conflicts\n const conflicts: MergeConflict[] = [];\n\n // Check for duplicate exports\n for (const local of localExports) {\n const duplicate = incomingExports.find((e) => e.name === local.name);\n if (duplicate && local.value !== duplicate.value) {\n conflicts.push({\n type: 'duplicate_export',\n name: local.name,\n localLine: local.line,\n incomingLine: duplicate.line,\n });\n }\n }\n\n // Check for duplicate aliases\n for (const local of localAliases) {\n const duplicate = incomingAliases.find((a) => a.name === local.name);\n if (duplicate && local.value !== duplicate.value) {\n conflicts.push({\n type: 'duplicate_alias',\n name: local.name,\n localLine: local.line,\n incomingLine: duplicate.line,\n });\n }\n }\n\n // Build merged content\n let mergedContent = incomingContent;\n\n // Append preserved blocks at the end\n if (preservedBlocks.length > 0) {\n mergedContent += '\\n\\n';\n mergedContent += '# ============================================\\n';\n mergedContent += '# LOCAL CUSTOMIZATIONS (preserved by tuck)\\n';\n mergedContent += '# ============================================\\n\\n';\n\n for (const block of preservedBlocks) {\n mergedContent += block.content + '\\n\\n';\n }\n }\n\n return {\n content: mergedContent.trim() + '\\n',\n preservedBlocks: preservedBlocks.length,\n incomingBlocks: 1,\n conflicts,\n };\n};\n\n/**\n * Generate a diff-like preview of what will change\n */\nexport const generateMergePreview = async (\n localPath: string,\n incomingContent: string\n): Promise<string> => {\n const expandedPath = expandPath(localPath);\n\n if (!(await pathExists(expandedPath))) {\n return `New file will be created:\\n${incomingContent.slice(0, 500)}${incomingContent.length > 500 ? '...' : ''}`;\n }\n\n const localContent = await readFile(expandedPath, 'utf-8');\n const preservedBlocks = findPreservedBlocks(localContent);\n const localExports = parseExports(localContent);\n const incomingExports = parseExports(incomingContent);\n\n const lines: string[] = [];\n\n lines.push('=== Merge Preview ===');\n lines.push('');\n\n // Show preserved blocks\n if (preservedBlocks.length > 0) {\n lines.push(`📌 ${preservedBlocks.length} block(s) will be preserved:`);\n for (const block of preservedBlocks) {\n lines.push(` - Lines ${block.lineStart}-${block.lineEnd} (${block.marker})`);\n }\n lines.push('');\n }\n\n // Show export changes\n const newExports = incomingExports.filter(\n (e) => !localExports.find((l) => l.name === e.name)\n );\n const changedExports = incomingExports.filter((e) => {\n const local = localExports.find((l) => l.name === e.name);\n return local && local.value !== e.value;\n });\n\n if (newExports.length > 0) {\n lines.push(`➕ ${newExports.length} new export(s):`);\n for (const exp of newExports.slice(0, 5)) {\n lines.push(` + ${exp.name}=${exp.value.slice(0, 50)}`);\n }\n if (newExports.length > 5) {\n lines.push(` ... and ${newExports.length - 5} more`);\n }\n lines.push('');\n }\n\n if (changedExports.length > 0) {\n lines.push(`🔄 ${changedExports.length} export(s) will be updated:`);\n for (const exp of changedExports.slice(0, 5)) {\n const local = localExports.find((l) => l.name === exp.name);\n lines.push(` ~ ${exp.name}: \"${local?.value.slice(0, 20)}...\" → \"${exp.value.slice(0, 20)}...\"`);\n }\n if (changedExports.length > 5) {\n lines.push(` ... and ${changedExports.length - 5} more`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n};\n\n/**\n * Check if content has any preserve markers\n */\nexport const hasPreserveMarkers = (content: string): boolean => {\n return PRESERVE_MARKERS.some((marker) => content.includes(marker));\n};\n\n/**\n * Add a preserve marker to content\n */\nexport const addPreserveMarker = (content: string, marker = '# tuck:preserve'): string => {\n return `${marker}\\n${content}`;\n};\n","import { Command } from 'commander';\nimport { prompts, logger, colors as c } from '../ui/index.js';\nimport { collapsePath } from '../lib/paths.js';\nimport {\n listSnapshots,\n getSnapshot,\n getLatestSnapshot,\n restoreSnapshot,\n restoreFileFromSnapshot,\n deleteSnapshot,\n getSnapshotsSize,\n formatSnapshotSize,\n formatSnapshotDate,\n Snapshot,\n} from '../lib/timemachine.js';\n\nexport interface UndoOptions {\n list?: boolean;\n latest?: boolean;\n file?: string;\n delete?: string;\n force?: boolean;\n dryRun?: boolean;\n}\n\n/**\n * Display a list of available snapshots\n */\nconst showSnapshotList = async (): Promise<void> => {\n const snapshots = await listSnapshots();\n\n if (snapshots.length === 0) {\n logger.warning('No backup snapshots found');\n logger.dim('Snapshots are created automatically when using `tuck apply`');\n return;\n }\n\n logger.heading('Backup Snapshots:');\n logger.blank();\n\n for (const snapshot of snapshots) {\n const date = formatSnapshotDate(snapshot.id);\n const fileCount = snapshot.files.filter((f) => f.existed).length;\n\n console.log(c.cyan(` ${snapshot.id}`));\n console.log(c.dim(` Date: ${date}`));\n console.log(c.dim(` Reason: ${snapshot.reason}`));\n console.log(c.dim(` Files: ${fileCount} file(s) backed up`));\n console.log(c.dim(` Machine: ${snapshot.machine}`));\n console.log();\n }\n\n const totalSize = await getSnapshotsSize();\n logger.dim(`Total backup size: ${formatSnapshotSize(totalSize)}`);\n logger.blank();\n logger.info('To restore a snapshot: tuck undo <snapshot-id>');\n logger.info('To restore the latest: tuck undo --latest');\n};\n\n/**\n * Display details of a specific snapshot\n */\nconst showSnapshotDetails = (snapshot: Snapshot): void => {\n console.log();\n console.log(c.bold('Snapshot Details:'));\n console.log(c.dim(` ID: ${snapshot.id}`));\n console.log(c.dim(` Date: ${formatSnapshotDate(snapshot.id)}`));\n console.log(c.dim(` Reason: ${snapshot.reason}`));\n console.log(c.dim(` Machine: ${snapshot.machine}`));\n console.log();\n console.log(c.bold('Files in snapshot:'));\n\n for (const file of snapshot.files) {\n if (file.existed) {\n console.log(c.dim(` ok ${collapsePath(file.originalPath)}`));\n } else {\n console.log(c.dim(` - ${collapsePath(file.originalPath)} (did not exist)`));\n }\n }\n console.log();\n};\n\n/**\n * Restore from a specific snapshot\n */\nconst restoreFromSnapshot = async (snapshotId: string, options: UndoOptions): Promise<void> => {\n const snapshot = await getSnapshot(snapshotId);\n\n if (!snapshot) {\n logger.error(`Snapshot not found: ${snapshotId}`);\n const snapshots = await listSnapshots();\n if (snapshots.length > 0) {\n logger.info('Available snapshots:');\n for (const s of snapshots.slice(0, 5)) {\n logger.dim(` ${s.id} - ${formatSnapshotDate(s.id)}`);\n }\n if (snapshots.length > 5) {\n logger.dim(` ... and ${snapshots.length - 5} more`);\n }\n }\n return;\n }\n\n // Show snapshot details\n showSnapshotDetails(snapshot);\n\n // Confirm unless --force or dry-run\n if (!options.force && !options.dryRun) {\n const backedUpCount = snapshot.files.filter((f) => f.existed).length;\n const confirmed = await prompts.confirm(\n `Restore ${backedUpCount} file(s) from this snapshot?`,\n true\n );\n\n if (!confirmed) {\n logger.info('Restore cancelled');\n return;\n }\n }\n\n // Dry run\n if (options.dryRun) {\n logger.heading('Dry run - would restore:');\n for (const file of snapshot.files) {\n if (file.existed) {\n logger.file('modify', collapsePath(file.originalPath));\n } else {\n logger.file('delete', `${collapsePath(file.originalPath)} (would remove)`);\n }\n }\n return;\n }\n\n // Restore\n logger.info('Restoring files...');\n const restoredFiles = await restoreSnapshot(snapshotId);\n\n logger.blank();\n logger.success(`Restored ${restoredFiles.length} file(s)`);\n\n for (const file of restoredFiles) {\n logger.dim(` ok ${collapsePath(file)}`);\n }\n};\n\n/**\n * Restore a single file from a snapshot\n */\nconst restoreSingleFile = async (\n snapshotId: string,\n filePath: string,\n options: UndoOptions\n): Promise<void> => {\n const snapshot = await getSnapshot(snapshotId);\n\n if (!snapshot) {\n logger.error(`Snapshot not found: ${snapshotId}`);\n return;\n }\n\n // Dry run\n if (options.dryRun) {\n logger.info(`Would restore ${filePath} from snapshot ${snapshotId}`);\n return;\n }\n\n // Restore the file\n await restoreFileFromSnapshot(snapshotId, filePath);\n logger.success(`Restored ${filePath}`);\n};\n\n/**\n * Delete a snapshot\n */\nconst removeSnapshot = async (snapshotId: string, options: UndoOptions): Promise<void> => {\n const snapshot = await getSnapshot(snapshotId);\n\n if (!snapshot) {\n logger.error(`Snapshot not found: ${snapshotId}`);\n return;\n }\n\n // Confirm unless --force\n if (!options.force) {\n showSnapshotDetails(snapshot);\n const confirmed = await prompts.confirm('Delete this snapshot permanently?', false);\n\n if (!confirmed) {\n logger.info('Deletion cancelled');\n return;\n }\n }\n\n await deleteSnapshot(snapshotId);\n logger.success(`Deleted snapshot: ${snapshotId}`);\n};\n\n/**\n * Interactive undo selection\n */\nconst runInteractiveUndo = async (): Promise<void> => {\n prompts.intro('tuck undo');\n\n const snapshots = await listSnapshots();\n\n if (snapshots.length === 0) {\n prompts.log.warning('No backup snapshots available');\n prompts.note('Snapshots are created when using `tuck apply`', 'Info');\n return;\n }\n\n // Let user select a snapshot\n const snapshotOptions = snapshots.map((s) => ({\n value: s.id,\n label: `${s.id} - ${s.reason.slice(0, 40)}${s.reason.length > 40 ? '...' : ''}`,\n hint: `${s.files.filter((f) => f.existed).length} files`,\n }));\n\n const selectedId = await prompts.select('Select a snapshot to restore:', snapshotOptions);\n\n const snapshot = await getSnapshot(selectedId);\n if (!snapshot) {\n prompts.log.error('Snapshot not found');\n return;\n }\n\n // Show what will be restored\n console.log();\n prompts.log.info('Files in this snapshot:');\n for (const file of snapshot.files.slice(0, 10)) {\n if (file.existed) {\n console.log(c.dim(` ${collapsePath(file.originalPath)}`));\n }\n }\n if (snapshot.files.length > 10) {\n console.log(c.dim(` ... and ${snapshot.files.length - 10} more`));\n }\n console.log();\n\n // Confirm\n const confirmed = await prompts.confirm('Restore these files?', true);\n\n if (!confirmed) {\n prompts.cancel('Restore cancelled');\n return;\n }\n\n // Restore\n const spinner = prompts.spinner();\n spinner.start('Restoring files...');\n\n const restoredFiles = await restoreSnapshot(selectedId);\n\n spinner.stop(`Restored ${restoredFiles.length} files`);\n\n prompts.outro('Done!');\n};\n\n/**\n * Main undo command handler\n */\nconst runUndo = async (snapshotId: string | undefined, options: UndoOptions): Promise<void> => {\n // Handle --list\n if (options.list) {\n await showSnapshotList();\n return;\n }\n\n // Handle --delete\n if (options.delete) {\n await removeSnapshot(options.delete, options);\n return;\n }\n\n // Handle --latest\n if (options.latest) {\n const latest = await getLatestSnapshot();\n if (!latest) {\n logger.warning('No backup snapshots available');\n return;\n }\n await restoreFromSnapshot(latest.id, options);\n return;\n }\n\n // Handle specific snapshot ID\n if (snapshotId) {\n // Check if we're restoring a single file\n if (options.file) {\n await restoreSingleFile(snapshotId, options.file, options);\n } else {\n await restoreFromSnapshot(snapshotId, options);\n }\n return;\n }\n\n // No arguments - run interactive mode\n await runInteractiveUndo();\n};\n\nexport const undoCommand = new Command('undo')\n .description('Restore files from a Time Machine backup snapshot')\n .argument('[snapshot-id]', 'Snapshot ID to restore (format: YYYY-MM-DD-HHMMSS)')\n .option('-l, --list', 'List all available backup snapshots')\n .option('--latest', 'Restore the most recent snapshot')\n .option('--file <path>', 'Restore a single file from the snapshot')\n .option('--delete <id>', 'Delete a specific snapshot')\n .option('-f, --force', 'Skip confirmation prompts')\n .option('--dry-run', 'Show what would be restored without making changes')\n .action(async (snapshotId: string | undefined, options: UndoOptions) => {\n await runUndo(snapshotId, options);\n });\n","import { Command } from 'commander';\nimport { prompts, logger, banner, colors as c } from '../ui/index.js';\nimport { getTuckDir, collapsePath, expandPath } from '../lib/paths.js';\nimport { loadManifest, getTrackedFileBySource } from '../lib/manifest.js';\nimport { detectDotfiles, DETECTION_CATEGORIES, DetectedFile } from '../lib/detect.js';\nimport { NotInitializedError } from '../errors.js';\nimport { trackFilesWithProgress, type FileToTrack } from '../lib/fileTracking.js';\nimport { shouldExcludeFromBin } from '../lib/binary.js';\nimport { isIgnored } from '../lib/tuckignore.js';\n\nexport interface ScanOptions {\n all?: boolean;\n category?: string;\n json?: boolean;\n quick?: boolean;\n}\n\ninterface SelectableFile extends DetectedFile {\n selected: boolean;\n alreadyTracked: boolean;\n}\n\n/**\n * Group selectable files by category\n */\nconst groupSelectableByCategory = (files: SelectableFile[]): Record<string, SelectableFile[]> => {\n const grouped: Record<string, SelectableFile[]> = {};\n\n for (const file of files) {\n if (!grouped[file.category]) {\n grouped[file.category] = [];\n }\n grouped[file.category].push(file);\n }\n\n return grouped;\n};\n\n/**\n * Display detected files grouped by category\n */\nconst displayGroupedFiles = (files: SelectableFile[], showAll: boolean): void => {\n const grouped = groupSelectableByCategory(files);\n const categories = Object.keys(grouped).sort((a, b) => {\n // Sort by category order in DETECTION_CATEGORIES\n const order = Object.keys(DETECTION_CATEGORIES);\n return order.indexOf(a) - order.indexOf(b);\n });\n\n for (const category of categories) {\n const categoryFiles = grouped[category];\n const config = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n const newFiles = categoryFiles.filter((f) => !f.alreadyTracked);\n const trackedFiles = categoryFiles.filter((f) => f.alreadyTracked);\n\n console.log();\n console.log(\n c.bold(`${config.icon} ${config.name}`) +\n c.dim(` (${newFiles.length} new, ${trackedFiles.length} tracked)`)\n );\n console.log(c.dim('─'.repeat(50)));\n\n for (const file of categoryFiles) {\n if (!showAll && file.alreadyTracked) continue;\n\n const status = file.selected ? c.green('[x]') : c.dim('[ ]');\n const name = file.path;\n const tracked = file.alreadyTracked ? c.dim(' (tracked)') : '';\n const sensitive = file.sensitive ? c.yellow(' [!]') : '';\n const dir = file.isDirectory ? c.cyan(' [dir]') : '';\n\n console.log(` ${status} ${name}${dir}${sensitive}${tracked}`);\n console.log(c.dim(` ${file.description}`));\n }\n }\n};\n\n/**\n * Interactive file selection\n */\nconst runInteractiveSelection = async (files: SelectableFile[]): Promise<SelectableFile[]> => {\n const newFiles = files.filter((f) => !f.alreadyTracked);\n\n if (newFiles.length === 0) {\n prompts.log.success('All detected dotfiles are already being tracked!');\n return [];\n }\n\n // Group files for selection\n const grouped = groupSelectableByCategory(newFiles);\n const selectedFiles: SelectableFile[] = [];\n\n // Ask for each category\n for (const [category, categoryFiles] of Object.entries(grouped)) {\n const config = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n\n console.log();\n console.log(c.bold(`${config.icon} ${config.name}`));\n console.log(c.dim(config.description || ''));\n console.log();\n\n // Create options for multiselect\n const options = categoryFiles.map((file: SelectableFile) => {\n let label = file.path;\n if (file.sensitive) {\n label += c.yellow(' [!]');\n }\n if (file.isDirectory) {\n label += c.cyan(' [dir]');\n }\n\n return {\n value: file.path,\n label,\n hint: file.description,\n };\n });\n\n // Pre-select all non-sensitive files by default\n const nonSensitiveFiles = categoryFiles.filter((f) => !f.sensitive);\n const initialValues = nonSensitiveFiles.map((f) => f.path);\n\n const selected = await prompts.multiselect(\n `Select files to track from ${config.name}:`,\n options,\n { initialValues }\n );\n\n // Mark selected files\n for (const file of categoryFiles) {\n if (selected.includes(file.path)) {\n file.selected = true;\n selectedFiles.push(file);\n }\n }\n }\n\n return selectedFiles;\n};\n\n/**\n * Quick display mode - just show what's detected\n */\nconst runQuickScan = async (files: SelectableFile[]): Promise<void> => {\n const newFiles = files.filter((f) => !f.alreadyTracked);\n const trackedFiles = files.filter((f) => f.alreadyTracked);\n\n console.log();\n console.log(\n c.bold.cyan('Detected Dotfiles: ') +\n c.white(`${newFiles.length} new, ${trackedFiles.length} already tracked`)\n );\n\n displayGroupedFiles(files, false);\n\n console.log();\n console.log(c.dim('─'.repeat(60)));\n console.log();\n\n if (newFiles.length > 0) {\n logger.info(`Found ${newFiles.length} new dotfiles to track`);\n logger.dim('Run `tuck scan` (without --quick) to interactively select files');\n logger.dim('Or run `tuck add <path>` to add specific files');\n } else {\n logger.success('All detected dotfiles are already being tracked!');\n }\n};\n\n/**\n * Summary display after selection\n */\nconst showSummary = (selected: SelectableFile[]): void => {\n if (selected.length === 0) {\n logger.info('No files selected');\n return;\n }\n\n console.log();\n console.log(c.bold.cyan(`Selected ${selected.length} files to track:`));\n console.log(c.dim('─'.repeat(50)));\n console.log();\n\n const grouped = groupSelectableByCategory(selected);\n\n for (const [category, files] of Object.entries(grouped)) {\n const config = DETECTION_CATEGORIES[category] || { icon: '-', name: category };\n console.log(c.bold(`${config.icon} ${config.name}`));\n\n for (const file of files) {\n const sensitive = file.sensitive ? c.yellow(' ⚠') : '';\n console.log(c.dim(` • ${collapsePath(file.path)}${sensitive}`));\n }\n console.log();\n }\n\n // Show warnings for sensitive files\n const sensitiveFiles = selected.filter((f) => f.sensitive);\n if (sensitiveFiles.length > 0) {\n console.log(c.yellow('⚠ Warning: Some files may contain sensitive data'));\n console.log(c.dim(' Make sure your repository is private!'));\n console.log();\n }\n};\n\n/**\n * Add selected files with beautiful progress display\n */\nconst addFilesWithProgress = async (\n selected: SelectableFile[],\n tuckDir: string\n): Promise<number> => {\n // Convert SelectableFile to FileToTrack\n const filesToTrack: FileToTrack[] = selected.map((f) => ({\n path: f.path,\n category: f.category,\n }));\n\n // Use the shared tracking utility\n const result = await trackFilesWithProgress(filesToTrack, tuckDir, {\n showCategory: true,\n actionVerb: 'Tracking',\n });\n\n return result.succeeded;\n};\n\n/**\n * Main scan function\n */\nconst runScan = async (options: ScanOptions): Promise<void> => {\n const tuckDir = getTuckDir();\n\n // Check if tuck is initialized\n try {\n await loadManifest(tuckDir);\n } catch {\n throw new NotInitializedError();\n }\n\n // Detect dotfiles\n const spinner = prompts.spinner();\n spinner.start('Scanning for dotfiles...');\n\n const detected = await detectDotfiles();\n\n spinner.stop(`Found ${detected.length} dotfiles on this system`);\n\n if (detected.length === 0) {\n logger.warning('No common dotfiles detected on this system');\n return;\n }\n\n // Check which files are already tracked\n const selectableFiles: SelectableFile[] = [];\n\n for (const file of detected) {\n const tracked = await getTrackedFileBySource(tuckDir, file.path);\n\n // Skip if in .tuckignore\n if (await isIgnored(tuckDir, file.path)) {\n continue;\n }\n\n // Skip if binary executable in bin directory\n if (await shouldExcludeFromBin(expandPath(file.path))) {\n continue;\n }\n\n selectableFiles.push({\n ...file,\n selected: true, // All selected by default\n alreadyTracked: tracked !== null,\n });\n }\n\n // Filter by category if specified\n let filesToShow = selectableFiles;\n if (options.category) {\n filesToShow = selectableFiles.filter((f) => f.category === options.category);\n if (filesToShow.length === 0) {\n logger.warning(`No dotfiles found in category: ${options.category}`);\n logger.info('Available categories:');\n for (const [key, config] of Object.entries(DETECTION_CATEGORIES)) {\n console.log(c.dim(` ${config.icon} ${key} - ${config.name}`));\n }\n return;\n }\n }\n\n // JSON output\n if (options.json) {\n console.log(JSON.stringify(filesToShow, null, 2));\n return;\n }\n\n // Quick mode - just display\n if (options.quick) {\n await runQuickScan(filesToShow);\n return;\n }\n\n // Interactive mode\n banner();\n prompts.intro('tuck scan');\n\n const newFiles = filesToShow.filter((f) => !f.alreadyTracked);\n const trackedCount = filesToShow.filter((f) => f.alreadyTracked).length;\n\n prompts.log.info(\n `Found ${filesToShow.length} dotfiles (${newFiles.length} new, ${trackedCount} tracked)`\n );\n\n if (newFiles.length === 0) {\n prompts.log.success('All detected dotfiles are already being tracked!');\n prompts.outro('Nothing to do');\n return;\n }\n\n // Ask how to proceed\n const action = await prompts.select('How would you like to proceed?', [\n {\n value: 'all',\n label: 'Track all new files',\n hint: `Add all ${newFiles.length} files`,\n },\n {\n value: 'select',\n label: 'Select files to track',\n hint: 'Choose which files to add',\n },\n {\n value: 'preview',\n label: 'Just show me what was found',\n hint: 'Display files without tracking',\n },\n ]);\n\n if (action === 'preview') {\n displayGroupedFiles(filesToShow, options.all || false);\n prompts.outro('Run `tuck scan` again to select files');\n return;\n }\n\n let selected: SelectableFile[];\n\n if (action === 'all') {\n selected = newFiles.map((f) => ({ ...f, selected: true }));\n } else {\n selected = await runInteractiveSelection(filesToShow);\n }\n\n if (selected.length === 0) {\n prompts.cancel('No files selected');\n return;\n }\n\n // Show summary of what will be tracked\n showSummary(selected);\n\n const confirmed = await prompts.confirm(`Track these ${selected.length} files?`, true);\n\n if (!confirmed) {\n prompts.cancel('Operation cancelled');\n return;\n }\n\n // Add the files with beautiful progress display\n const addedCount = await addFilesWithProgress(selected, tuckDir);\n\n if (addedCount > 0) {\n // Ask if user wants to sync now\n console.log();\n const shouldSync = await prompts.confirm('Would you like to sync these changes now?', true);\n\n if (shouldSync) {\n console.log();\n const { runSync } = await import('./sync.js');\n await runSync({});\n } else {\n prompts.outro(\"Run 'tuck sync' when you're ready to commit changes\");\n }\n } else {\n prompts.outro('No files were added');\n }\n};\n\nexport const scanCommand = new Command('scan')\n .description('Scan system for dotfiles and select which to track')\n .option('-a, --all', 'Show all files including already tracked ones')\n .option('-c, --category <name>', 'Filter by category (shell, git, editors, etc.)')\n .option('-q, --quick', 'Quick scan - just show detected files without interactive selection')\n .option('--json', 'Output results as JSON')\n .action(async (options: ScanOptions) => {\n await runScan(options);\n });\n","/**\n * Auto-update checker for tuck CLI\n * Checks for updates on npm registry and prompts user to update\n */\n\nimport updateNotifier from 'update-notifier';\nimport { execSync, spawnSync } from 'child_process';\nimport chalk from 'chalk';\nimport boxen from 'boxen';\nimport { createInterface } from 'readline';\nimport { APP_NAME, VERSION } from '../constants.js';\n\n// Package info for update-notifier\nconst pkg = {\n name: '@prnv/tuck',\n version: VERSION,\n};\n\n/**\n * Detect which package manager was used to install tuck\n * Checks npm_config_user_agent first, then falls back to detection\n */\nconst detectPackageManager = (): 'npm' | 'pnpm' => {\n // Check if pnpm is in the user agent (set when running via pnpm)\n const userAgent = process.env.npm_config_user_agent || '';\n if (userAgent.includes('pnpm')) {\n return 'pnpm';\n }\n\n // Try to detect if tuck was installed via pnpm global\n try {\n const pnpmList = execSync('pnpm list -g --depth=0 2>/dev/null', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n if (pnpmList.includes('@prnv/tuck')) {\n return 'pnpm';\n }\n } catch {\n // pnpm not available or command failed\n }\n\n // Default to npm\n return 'npm';\n};\n\n/**\n * Get the update command for the detected package manager\n */\nconst getUpdateCommand = (packageManager: 'npm' | 'pnpm'): string => {\n if (packageManager === 'pnpm') {\n return 'pnpm update -g @prnv/tuck';\n }\n return 'npm update -g @prnv/tuck';\n};\n\n/**\n * Wait for user to press Enter or cancel\n * Returns true if Enter pressed, false if cancelled\n */\nconst waitForEnterOrCancel = (): Promise<boolean> => {\n return new Promise((resolve) => {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n // Handle Ctrl+C\n rl.on('close', () => {\n resolve(false);\n });\n\n // Handle Enter\n rl.on('line', () => {\n rl.close();\n resolve(true);\n });\n\n // Handle SIGINT (Ctrl+C)\n process.on('SIGINT', () => {\n rl.close();\n resolve(false);\n });\n });\n};\n\n/**\n * Execute the update command\n */\nconst executeUpdate = (packageManager: 'npm' | 'pnpm'): boolean => {\n const command = getUpdateCommand(packageManager);\n console.log(chalk.dim(`\\nUpdating ${APP_NAME} via ${packageManager}...`));\n\n try {\n const result = spawnSync(packageManager, ['update', '-g', '@prnv/tuck'], {\n stdio: 'inherit',\n shell: true,\n });\n\n if (result.status === 0) {\n console.log(chalk.green(`\\nSuccessfully updated ${APP_NAME}!`));\n console.log(chalk.dim('Restart tuck to use the new version.\\n'));\n return true;\n } else {\n console.log(chalk.red('\\nUpdate failed.'));\n console.log(chalk.dim(`Run manually: ${command}\\n`));\n return false;\n }\n } catch (error) {\n console.log(chalk.red('\\nUpdate failed.'));\n console.log(chalk.dim(`Run manually: ${command}\\n`));\n return false;\n }\n};\n\n/**\n * Check if running in an environment where we should skip update checks\n */\nconst shouldSkipUpdateCheck = (): boolean => {\n // Skip in CI environments\n if (process.env.CI) {\n return true;\n }\n\n // Skip if running via npx (one-time execution)\n const execPath = process.env.npm_execpath || '';\n if (execPath.includes('npx')) {\n return true;\n }\n\n // Skip if NO_UPDATE_CHECK is set\n if (process.env.NO_UPDATE_CHECK) {\n return true;\n }\n\n // Skip if not a TTY (non-interactive)\n if (!process.stdin.isTTY) {\n return true;\n }\n\n return false;\n};\n\n/**\n * Main function to check for updates and prompt user\n * Called at startup before command execution\n */\nexport const checkForUpdates = async (): Promise<void> => {\n // Skip in certain environments\n if (shouldSkipUpdateCheck()) {\n return;\n }\n\n // Check for updates using update-notifier\n // It caches results and only checks periodically (default: once per day)\n const notifier = updateNotifier({\n pkg,\n updateCheckInterval: 1000 * 60 * 60 * 24, // 24 hours\n });\n\n // If no update available, return early\n if (!notifier.update || notifier.update.latest === VERSION) {\n return;\n }\n\n const { latest } = notifier.update;\n const packageManager = detectPackageManager();\n const updateCommand = getUpdateCommand(packageManager);\n\n // Show update notification box\n const message = [\n '',\n chalk.bold(`Update available: ${chalk.red(VERSION)} ${chalk.dim('->')} ${chalk.green(latest)}`),\n '',\n chalk.dim('Press Enter to update, or Ctrl+C to skip'),\n '',\n ].join('\\n');\n\n console.log(\n boxen(message, {\n padding: { top: 0, bottom: 0, left: 2, right: 2 },\n margin: { top: 1, bottom: 0, left: 0, right: 0 },\n borderStyle: 'round',\n borderColor: 'cyan',\n textAlignment: 'center',\n })\n );\n\n // Wait for user input\n const shouldUpdate = await waitForEnterOrCancel();\n\n if (shouldUpdate) {\n const success = executeUpdate(packageManager);\n if (success) {\n // Exit after successful update so user uses new version\n process.exit(0);\n }\n // If update failed, continue with current version\n } else {\n // User skipped update\n console.log(chalk.dim(`\\nSkipped. Run '${updateCommand}' to update later.\\n`));\n }\n};\n"],"mappings":"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","names":["logSymbols","figures","indent","p","logSymbols","spinner","text","p","logSymbols","figures","figures","pkg","homedir","join","dirname","z","chalk","z","fileStrategySchema","readFile","writeFile","fetch","join","execFile","promisify","execFileAsync","log","platform","execFile","promisify","execFileAsync","validateRepoName","homedir","join","readFile","pathExists","platform","writeFile","dirname","spawn","resolve","unlink","password","join","basename","isAbsolute","stat","isDirectory","readFile","stat","readdir","join","dirname","basename","constants","content","chalk","ensureDir","dirname","spinner","resolve","join","copy","ensureDir","pathExists","promisify","chalk","join","stat","confirm","join","readFile","writeFile","p","readFile","stat","p","readFile","writeFile","chmod","stat","join","ensureDir","readFile","writeFile","unlink","stat","dirname","basename","join","execFile","promisify","z","execFileAsync","p","p","Command","init_secrets","spinner","simpleGit","scanContent","p","Command","join","init_secrets","fetch","c","spinner","Command","chalk","Command","join","writeFile","ensureDir","execFile","promisify","execFileAsync","COMMON_DOTFILE_REPO_NAMES","platform","execFile","promisify","execFileAsync","spinner","execFile","promisify","execFileAsync","GitLabProvider","copy","readFile","rm","validateGitUrl","ensureDir","join","writeFile","execFile","promisify","execFileAsync","spinner","readdir","p","getPreferredRemoteProtocol","DETECTION_CATEGORIES","hostname","removeRemote","stat","runRestore","Command","Command","basename","stat","basename","dirname","PRIVATE_KEY_PATTERNS","SENSITIVE_FILE_PATTERNS","basename","isSensitiveFile","sizeCheck","scanAndHandleSecrets","confirm","scanAndHandleSecrets","runSync","Command","Command","join","validateAndPrepareFiles","confirm","Command","remoteUrl","confirm","Command","Command","fetch","Command","Command","boxen","logSymbols","figures","Command","groupByCategory","group","Command","join","readFile","join","repoExists","systemChecksum","repoChecksum","Command","Command","resolve","confirm","colors","currentValue","spinner","Command","Command","join","readFile","rm","chmod","stat","ensureDir","tmpdir","join","dirname","readdir","readFile","writeFile","rm","stat","copy","ensureDir","pathExists","homedir","pathExists","readdir","join","stat","readFile","readFile","stat","chmod","join","tmpdir","ensureDir","readFile","writeFile","dirname","spinner","rm","Command","Command","spinner","Command","Command","spinner","runSync","Command","init_secrets","chalk","boxen","resolve","Command","chalk"]}
|