@cellajs/cli 0.0.6 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cella-cli.ts","../src/cli.ts","../src/utils/colors.ts","../src/utils/env.ts","../src/utils/config.ts","../src/config/types.ts","../src/utils/module-territory.ts","../src/utils/display.ts","../package.json","../src/utils/managed-files.ts","../src/utils/overrides.ts","../src/services/analyze.ts","../src/utils/diff.ts","../src/utils/cleanup.ts","../src/utils/git.ts","../src/utils/manifest.ts","../src/services/analyze-core.ts","../src/services/merge-engine.ts","../src/services/audit.ts","../src/utils/audit-utils.ts","../src/utils/yaml.ts","../src/services/contributions.ts","../src/services/contrib-core.ts","../src/services/fork-utils.ts","../src/services/forks.ts","../src/services/sync.ts","../src/utils/gh.ts","../src/services/packages.ts","../src/services/stats.ts","../src/utils/coverage-utils.ts"],"sourcesContent":["#!/usr/bin/env tsx\n/**\n * Cella CLI v2 - Main entry point\n *\n * Worktree-based merge approach that isolates all merge operations\n * from the main repository until the final atomic rsync copy.\n */\n\nimport { existsSync, statSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport process from 'node:process';\nimport { parseCli } from './cli';\nimport type { CellaCliConfig } from './config/types';\nimport { runAnalyze } from './services/analyze';\nimport { runAudit } from './services/audit';\nimport { runContributions } from './services/contributions';\nimport { runForks } from './services/forks';\nimport { runStats } from './services/stats';\nimport { runSyncCommand } from './services/sync';\nimport { registerSignalHandlers } from './utils/cleanup';\nimport pc from './utils/colors';\nimport { loadConfig } from './utils/config';\nimport { getEnv } from './utils/env';\n\n/**\n * Determine the fork path.\n *\n * Priority:\n * 1. CELLA_FORK_PATH environment variable\n * 2. Current working directory (where the CLI is run from)\n *\n * Note: When run via pnpm filter, cwd may be cli/cella - we detect and navigate up.\n */\nfunction getForkPath(): string {\n const envPath = getEnv('CELLA_FORK_PATH');\n if (envPath) {\n const resolved = resolve(envPath);\n if (!existsSync(resolved) || !statSync(resolved).isDirectory()) {\n throw new Error(`CELLA_FORK_PATH is not a valid directory: ${resolved}`);\n }\n return resolved;\n }\n\n let cwd = process.cwd();\n\n // If running from within cli/cella (e.g., via pnpm --filter), go up to find the fork root\n if (cwd.endsWith('/cli/cella') || cwd.endsWith('\\\\cli\\\\cella')) {\n cwd = resolve(cwd, '../..');\n }\n\n return cwd;\n}\n\n/**\n * Pre-flight checks before running a service.\n *\n * The sync service cuts its own temporary branch from the trunk and owns its own clean/resume\n * state, so preflight no longer cares which branch you are on or whether the tree is clean — it\n * only verifies we are inside a git repository.\n */\nasync function preflight(forkPath: string): Promise<void> {\n if (!existsSync(join(forkPath, '.git'))) {\n throw new Error(`not a git repository: ${forkPath}`);\n }\n}\n\nfunction isHelpOrVersionRequest(): boolean {\n return (\n process.argv.slice(2).some((arg) => arg === '--help' || arg === '-h' || arg === '--version' || arg === '-v') ||\n process.argv[2] === 'help'\n );\n}\n\n/**\n * Main entry point.\n */\nasync function main(): Promise<void> {\n // Register signal handlers for cleanup\n registerSignalHandlers();\n\n try {\n // Determine fork path\n const forkPath = getForkPath();\n\n if (isHelpOrVersionRequest()) {\n await parseCli({ settings: { upstreamUrl: '', upstreamBranch: 'main' } } as CellaCliConfig, forkPath);\n return;\n }\n\n // Load config\n const userConfig = await loadConfig(forkPath);\n\n // Parse CLI and get runtime config\n const config = await parseCli(userConfig, forkPath);\n\n // Run preflight checks (except for services that operate on other fork paths)\n if (!['audit', 'forks', 'contributions', 'stats'].includes(config.service)) {\n await preflight(forkPath);\n }\n\n // Route to service\n switch (config.service) {\n case 'analyze': {\n await runAnalyze(config);\n break;\n }\n\n case 'sync': {\n await runSyncCommand(config);\n break;\n }\n\n case 'audit':\n await runAudit(config, { force: config.force, checkOverrides: config.checkOverrides });\n break;\n\n case 'forks':\n await runForks(config);\n break;\n\n case 'contributions':\n await runContributions(config);\n break;\n\n case 'stats':\n await runStats(config.forkPath, { verbose: config.verbose, refreshCoverage: config.coverage });\n break;\n }\n\n console.info();\n } catch (error) {\n console.error();\n console.error(`${pc.red('✗')} ${error instanceof Error ? error.message : 'unknown error'}`);\n process.exit(1);\n }\n}\n\nmain();\n","/**\n * CLI entry point for sync CLI v2.\n *\n * Parses command line arguments and routes to appropriate service.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport process from 'node:process';\nimport { select } from '@inquirer/prompts';\nimport { Command } from 'commander';\nimport type { AnalyzeScope, CellaCliConfig, RuntimeConfig, SyncService } from './config/types';\nimport pc from './utils/colors';\nimport { resolveUpstream } from './utils/config';\nimport { NAME, printHeader, setJsonMode, VERSION } from './utils/display';\nimport { printWarnings, validateOverrides } from './utils/overrides';\n\ntype CliServiceSelection = {\n service?: SyncService;\n options: CliOptionState;\n};\n\ntype CliOptionState = Pick<\n RuntimeConfig,\n | 'logFile'\n | 'verbose'\n | 'list'\n | 'json'\n | 'diff'\n | 'openDiff'\n | 'scope'\n | 'fork'\n | 'hard'\n | 'unpinned'\n | 'track'\n | 'force'\n | 'checkOverrides'\n | 'coverage'\n | 'directMerge'\n>;\n\ntype MenuContext = {\n hasForks: boolean;\n isUpstreamRepo: boolean;\n};\n\ntype ServiceOptionDefinition = {\n flags: string;\n description: string;\n};\n\ntype ServiceDefinition = {\n name: SyncService;\n description: string;\n options?: ServiceOptionDefinition[];\n includeInMenu?: (context: MenuContext) => boolean;\n menuDescription?: (context: MenuContext) => string;\n};\n\nfunction readOptions(opts: Record<string, unknown>): CliOptionState {\n const scope = typeof opts.scope === 'string' ? opts.scope : undefined;\n if (scope && scope !== 'all' && scope !== 'risk' && scope !== 'protected') {\n throw new Error(`invalid --scope '${scope}'. expected one of: all, risk, protected`);\n }\n const normalizedScope = scope as AnalyzeScope | undefined;\n\n return {\n logFile: opts.log === true,\n verbose: opts.verbose === true,\n list: opts.list === true,\n json: opts.json === true,\n diff: typeof opts.diff === 'string' ? opts.diff : undefined,\n openDiff: typeof opts.openDiff === 'string' ? opts.openDiff : undefined,\n scope: normalizedScope,\n fork: typeof opts.fork === 'string' ? opts.fork : undefined,\n hard: opts.hard === true,\n unpinned: opts.unpinned === true,\n track: opts.track === 'release' || opts.track === 'branch' ? opts.track : undefined,\n force: opts.force === true,\n checkOverrides: opts.checkOverrides === true,\n coverage: opts.coverage === true,\n directMerge: opts.directMerge === true,\n };\n}\n\nconst serviceDefinitions: ServiceDefinition[] = [\n {\n name: 'analyze',\n description: 'dry run to see what would change on sync',\n options: [\n { flags: '--log', description: 'write complete file list to cella-sync.log' },\n { flags: '--list', description: 'non-interactive output for tooling (one file per line)' },\n { flags: '--json', description: 'machine-readable output for tooling/agents' },\n { flags: '--scope <scope>', description: 'analyze scope for --list/--json: all|risk|protected' },\n { flags: '--track <mode>', description: 'override upstream tracking for this run: release|branch' },\n { flags: '--diff <path>', description: 'print unified diff for one file, then exit' },\n { flags: '--open-diff <path>', description: 'open a browser diff for one file, then exit' },\n ],\n includeInMenu: (context) => !context.isUpstreamRepo,\n },\n {\n name: 'sync',\n description: 'merge upstream changes into your app',\n options: [\n { flags: '--log', description: 'write complete file list to cella-sync.log' },\n { flags: '--hard', description: 'overwrite drifted files with upstream version (aggressive realignment)' },\n { flags: '--unpinned', description: 'ignore pinned files (except package.json) to resurface upstream changes' },\n { flags: '--track <mode>', description: 'override upstream tracking for this run: release|branch' },\n {\n flags: '--direct-merge',\n description: 'auto-merge (squash) the sync PR once checks pass — needs auto-merge enabled on the repo',\n },\n ],\n includeInMenu: (context) => !context.isUpstreamRepo,\n menuDescription: () => 'merge upstream changes + sync package.json',\n },\n {\n name: 'audit',\n description: 'check for outdated packages & vulnerabilities',\n options: [\n { flags: '--list', description: 'skip interactive update prompts after printing audit results' },\n { flags: '--force', description: 'bypass pnpm metadata cache for fresh registry data' },\n { flags: '--check-overrides', description: 'check which pnpm.overrides are still needed' },\n ],\n },\n {\n name: 'forks',\n description: 'sync downstream to local fork repositories',\n options: [\n { flags: '--fork <name>', description: 'pre-select fork by name (skips fork selection prompt)' },\n { flags: '--log', description: 'write complete file list to cella-sync.log for each synced fork' },\n { flags: '-V, --verbose', description: 'show detailed output during operations' },\n { flags: '--hard', description: 'overwrite drifted files with upstream version (aggressive realignment)' },\n ],\n includeInMenu: (context) => context.hasForks,\n },\n {\n name: 'contributions',\n description: 'pull and adopt changes from forks',\n options: [\n { flags: '--fork <name>', description: 'select a specific fork directly (skips fork selection)' },\n { flags: '--list', description: 'non-interactive output (one file per line)' },\n { flags: '--json', description: 'machine-readable JSON output for tooling/agents' },\n { flags: '--diff <path>', description: 'print the unified diff for a single contributed file, then exit' },\n ],\n includeInMenu: (context) => context.hasForks,\n },\n {\n name: 'stats',\n description: 'count files by category and workspace package',\n options: [\n { flags: '-V, --verbose', description: 'show detailed output during operations' },\n { flags: '--coverage', description: 'regenerate test coverage before showing the stats summary' },\n ],\n },\n];\n\nasync function getMenuContext(userConfig: CellaCliConfig, forkPath: string): Promise<MenuContext> {\n return {\n hasForks: (userConfig.forks?.length ?? 0) > 0,\n isUpstreamRepo: JSON.parse(readFileSync(join(forkPath, 'package.json'), 'utf8')).name === 'cella',\n };\n}\n\n/**\n * Build service menu choices, conditionally including optional services.\n */\nfunction buildServiceChoices(context: MenuContext) {\n // Pad service labels to align descriptions (longest label is 'contributions').\n const label = (name: string) => name.padEnd(14);\n const baseChoices = serviceDefinitions\n .filter((service) => service.includeInMenu?.(context) ?? true)\n .map((service) => ({\n value: service.name,\n name: `${label(service.name)}${pc.dim(service.menuDescription?.(context) ?? service.description)}`,\n }));\n\n return [\n ...baseChoices,\n { type: 'separator' as const, separator: '─'.repeat(40) },\n { value: 'exit' as const, name: pc.red(`${label('exit')}${pc.dim('quit without doing anything')}`) },\n ];\n}\n\nfunction addServiceCommand(\n program: Command,\n definition: ServiceDefinition,\n setSelection: (selection: CliServiceSelection) => void,\n) {\n const command = program.command(definition.name).description(definition.description);\n\n for (const option of definition.options ?? []) {\n command.option(option.flags, option.description);\n }\n\n command.action((opts) => {\n setSelection({\n service: definition.name,\n options: readOptions(opts),\n });\n });\n}\n\nfunction buildProgram(setSelection: (selection: CliServiceSelection) => void): Command {\n const program = new Command(NAME)\n .name('cella')\n .version(VERSION, '-v, --version', 'output the current version')\n .usage('[service] [options]')\n .helpOption('-h, --help', 'display help for a command')\n .showHelpAfterError()\n .addHelpText(\n 'after',\n [\n '',\n 'Examples:',\n ' $ cella analyze',\n ' $ cella analyze --json --scope risk',\n ' $ cella analyze --open-diff frontend/src/routes/index.tsx',\n ' $ cella sync --hard',\n ' $ cella sync --unpinned',\n ' $ cella sync --track branch',\n ' $ cella sync --direct-merge',\n ' $ cella audit --check-overrides',\n ' $ cella contributions --fork raak --json',\n ].join('\\n'),\n );\n\n for (const definition of serviceDefinitions) {\n addServiceCommand(program, definition, setSelection);\n }\n\n return program;\n}\n\nfunction parseCommandLine(argv: string[]): CliServiceSelection {\n if (argv.length <= 2) {\n return { options: readOptions({}) };\n }\n\n let selection: CliServiceSelection = { options: readOptions({}) };\n const program = buildProgram((nextSelection) => {\n selection = nextSelection;\n });\n\n program.parse(argv);\n return selection;\n}\n\nasync function promptForService(userConfig: CellaCliConfig, forkPath: string): Promise<SyncService> {\n const selected = await select<SyncService | 'exit'>({\n message: 'choose a service:',\n choices: buildServiceChoices(await getMenuContext(userConfig, forkPath)),\n loop: false,\n });\n\n if (selected === 'exit') {\n console.info(pc.dim('exiting...'));\n console.info();\n process.exit(0);\n }\n\n console.info();\n return selected;\n}\n\nfunction buildRuntimeConfig(\n userConfig: CellaCliConfig,\n forkPath: string,\n selection: CliServiceSelection,\n): RuntimeConfig {\n // Static fallback ref (branch tip). For release tracking the merge engine resolves\n // the concrete release-tag ref after fetching and writes it back to config.upstreamRef.\n const { branchRef } = resolveUpstream(userConfig.settings);\n\n return {\n ...userConfig,\n forkPath,\n upstreamRef: branchRef,\n service: selection.service ?? 'analyze',\n ...selection.options,\n };\n}\n\n/**\n * Parse CLI arguments and return configuration.\n */\nexport async function parseCli(userConfig: CellaCliConfig, forkPath: string): Promise<RuntimeConfig> {\n const selection = parseCommandLine(process.argv);\n\n // In machine-output modes (--json, --diff), reserve stdout for the payload/patch\n // and route all human output (header, warnings, spinner) to stderr.\n if (selection.options.json || selection.options.diff) setJsonMode(true);\n\n // Print header\n printHeader();\n\n // Validate config and show warnings\n const warnings = validateOverrides(userConfig, forkPath);\n if (warnings.length > 0) {\n printWarnings(warnings);\n console.info();\n }\n\n // If no service provided, prompt for it\n if (!selection.service) {\n selection.service = await promptForService(userConfig, forkPath);\n }\n\n return buildRuntimeConfig(userConfig, forkPath, selection);\n}\n","import process from 'node:process';\nimport { styleText } from 'node:util';\nimport { hasEnv } from './env';\n\ntype ColorStyle = 'blue' | 'bold' | 'cyan' | 'dim' | 'gray' | 'green' | 'magenta' | 'red' | 'white' | 'yellow';\n\nfunction colorsEnabled(): boolean {\n if (hasEnv('NO_COLOR')) return false;\n if (hasEnv('FORCE_COLOR')) return true;\n return !!process.stdout.isTTY;\n}\n\nfunction applyStyle(style: ColorStyle, text: string): string {\n if (!colorsEnabled()) return text;\n return styleText(style, text, { validateStream: false });\n}\n\nconst pc = {\n blue: (text: string) => applyStyle('blue', text),\n bold: (text: string) => applyStyle('bold', text),\n cyan: (text: string) => applyStyle('cyan', text),\n dim: (text: string) => applyStyle('dim', text),\n gray: (text: string) => applyStyle('gray', text),\n green: (text: string) => applyStyle('green', text),\n magenta: (text: string) => applyStyle('magenta', text),\n red: (text: string) => applyStyle('red', text),\n white: (text: string) => applyStyle('white', text),\n yellow: (text: string) => applyStyle('yellow', text),\n};\n\nexport default pc;\n","import process from 'node:process';\n\n/**\n * Centralized environment access for CLI/runtime integration points.\n */\nexport function getEnv(name: string): string | undefined {\n // biome-ignore lint/style/noProcessEnv: This module centralizes intentional CLI environment access.\n return process.env[name];\n}\n\nexport function hasEnv(name: string): boolean {\n // biome-ignore lint/style/noProcessEnv: This module centralizes intentional CLI environment access.\n return name in process.env;\n}\n\nexport function getEnvSnapshot(): NodeJS.ProcessEnv {\n // biome-ignore lint/style/noProcessEnv: This module centralizes intentional CLI environment access.\n return { ...process.env };\n}\n","/**\n * Config loading utilities for sync CLI.\n *\n * Shared between main entry point and forks service.\n */\n\nimport { existsSync, realpathSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { z } from 'zod';\nimport { type CellaCliConfig, cellaConfigSchema, type SyncSettings } from '../config/types';\nimport { resolveAppModuleFolders } from './module-territory';\n\n/** Default git remote name used to point at the upstream repository. */\nexport const DEFAULT_UPSTREAM_REMOTE = 'cella-upstream';\n\n/** Default branch used when a config omits `upstreamBranch`; also cella's fork-compare base. */\nexport const DEFAULT_BRANCH = 'main';\n\n/**\n * Prefix for the temporary integration branches that `cella sync` cuts per run\n * (e.g. `cella/sync/20260702-1430`).\n *\n * The three-segment shape (`cella/sync/<stamp>`) means it can never collide with a real branch\n * named `cella` or `cella/sync`.\n */\nexport const DEFAULT_SYNC_PREFIX = 'cella/sync';\n\n/**\n * Default trunk branch that `cella sync` cuts from and opens PRs into.\n */\nexport const DEFAULT_RELEASE_BASE = 'main';\n\n/**\n * Whether `branch` is one of the temporary integration branches `cella sync` cuts, i.e. it\n * lives under the internal `cella/sync/` namespace.\n */\nexport function isTemporarySyncBranch(branch: string): boolean {\n return branch.startsWith(`${DEFAULT_SYNC_PREFIX}/`);\n}\n\n/**\n * Resolve the trunk branch `cella sync` cuts the temporary branch from and PRs into.\n */\nexport function resolveReleaseBase(settings: SyncSettings): string {\n return settings.releaseBase ?? DEFAULT_RELEASE_BASE;\n}\n\n/**\n * Build a unique temporary integration branch name for a sync cycle, e.g.\n * `cella/sync/20260702-1430`. Cutting a fresh branch per cycle keeps each PR\n * scoped to that sync's upstream delta.\n */\nexport function buildTemporarySyncBranch(): string {\n const now = new Date();\n const pad = (n: number) => String(n).padStart(2, '0');\n const stamp = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}`;\n return `${DEFAULT_SYNC_PREFIX}/${stamp}`;\n}\n\n/**\n * Resolve the upstream tracking plan from sync settings.\n *\n * Single source of truth shared by the CLI entry point and the merge engine.\n * The concrete ref for release tracking (latest tag) can only be resolved after\n * fetching, so this returns a plan; the merge engine turns it into a ref.\n *\n * - `track`: 'release' (default) syncs to the latest release tag; 'branch' follows the tip.\n * - `branchRef`: `<DEFAULT_UPSTREAM_REMOTE>/<branch>` — the branch-track ref and static fallback.\n */\nexport function resolveUpstream(settings: SyncSettings): {\n track: 'release' | 'branch';\n branchRef: string;\n} {\n const track = settings.upstreamTrack ?? 'release';\n const branch = settings.upstreamBranch ?? DEFAULT_BRANCH;\n const branchRef = `${DEFAULT_UPSTREAM_REMOTE}/${branch}`;\n return { track, branchRef };\n}\n\n/**\n * Load cella.config.ts from a fork/repo path.\n */\nexport async function loadConfig(forkPath: string): Promise<CellaCliConfig> {\n const configPath = join(forkPath, 'cella.config.ts');\n\n if (!existsSync(configPath)) {\n throw new Error(`config file not found: ${configPath}`);\n }\n\n // Resolve symlinks and validate path stays within fork directory\n const realConfigPath = realpathSync(configPath);\n const realForkPath = realpathSync(resolve(forkPath));\n if (!realConfigPath.startsWith(`${realForkPath}/`)) {\n throw new Error('config path resolves outside fork directory');\n }\n\n let configModule: { default?: unknown };\n try {\n configModule = await import(realConfigPath);\n } catch (error) {\n // Syntax/runtime errors while evaluating the config must fail closed: a config that\n // cannot be loaded means sync protections (ignored/pinned) are unknown.\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`failed to load ${configPath}: ${message}`);\n }\n\n // Strict schema validation.\n const result = cellaConfigSchema.safeParse(configModule.default);\n if (!result.success) {\n throw new Error(`invalid ${configPath}:\\n${z.prettifyError(result.error)}`);\n }\n const config: CellaCliConfig = result.data;\n\n // Auto-derive fork-owned module folders (modules declaring `owner: 'app'`) and merge\n // them into ignored. This keeps app modules as fork territory: upstream never\n // adds/modifies/deletes them during sync, and the contributions service never offers\n // them back upstream. Derived entries always exist (they come from real files), so\n // config validation never warns about them.\n const appModuleFolders = resolveAppModuleFolders(realForkPath);\n if (appModuleFolders.length > 0) {\n const existing = config.overrides?.ignored ?? [];\n config.overrides = {\n ...config.overrides,\n ignored: [...new Set([...existing, ...appModuleFolders])],\n };\n }\n\n return config;\n}\n","/**\n * Sync CLI v2 - Configuration Types\n *\n * Simplified configuration for worktree-based merge approach.\n */\n\nimport { z } from 'zod';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// PUBLIC API - for cella.config.ts\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Valid package.json keys that can be synced */\nexport type PackageJsonSyncKey =\n | 'dependencies'\n | 'devDependencies'\n | 'peerDependencies'\n | 'optionalDependencies'\n | 'scripts'\n | 'engines'\n | 'packageManager'\n | 'overrides'\n | 'pnpm';\n\n/**\n * Sync settings - all configurable options for the sync CLI.\n * Hover over each property for documentation.\n */\nexport interface SyncSettings {\n /** Upstream repository URL (e.g., 'git@github.com:cellajs/cella.git') */\n upstreamUrl: string;\n\n /**\n * Upstream branch, used for `upstreamTrack: 'branch'` and for GitHub file links.\n * Defaults to 'main'.\n */\n upstreamBranch?: string;\n\n /**\n * How to track upstream cella. Defaults to 'release'.\n * - 'release' (default): sync to a published cella release tag (`v*`). Stable and\n * reviewable — each bump maps to a changelog. Uses the latest release.\n * - 'branch': follow the bleeding-edge tip of `upstreamBranch`. For cella\n * maintainers and forks doing active development on top of unreleased changes.\n */\n upstreamTrack?: 'release' | 'branch';\n\n /**\n * Trunk branch that `pnpm cella sync` cuts the temporary branch from and that you open the\n * squash-merge PR into. Defaults to 'main'. Cutting fresh from trunk each cycle keeps every\n * PR limited to that cycle's upstream delta (no accumulation) and `main` linear.\n */\n releaseBase?: string;\n\n /** Which package.json keys to sync (default: ['dependencies', 'devDependencies']) */\n packageJsonSync?: PackageJsonSyncKey[];\n\n /**\n * Automatically run packages sync after the sync service completes.\n * When true (default), the packages service is hidden from the menu\n * and runs automatically as part of sync.\n * Set to false to keep packages as a separate manual service.\n */\n syncWithPackages?: boolean;\n\n /**\n * How to link files in CLI output.\n * - 'commit' (default): Link to the commit that changed the file on GitHub.\n * - 'file': Link to the file in the repo at the upstream branch on GitHub.\n * - 'local': Deprecated (the upstream view worktree was replaced by browser diffs); treated as 'file'.\n */\n fileLinkMode?: 'commit' | 'file' | 'local';\n}\n\n/**\n * Configuration for a downstream fork repository that cella interacts with.\n *\n * Cella is the upstream/source-of-truth. For each fork it can:\n * - pull contributions FROM the fork's `pullBranch` (contributions service)\n * - run the normal temporary-branch sync flow inside the fork (forks service)\n */\nexport interface ForkConfig {\n /** Display name for the fork (also used as the contrib/<name> branch slug) */\n name: string;\n /** Local path to the fork repository (relative to this config or absolute) */\n localPath: string;\n /**\n * Git remote URL of the fork (e.g. 'git@github.com:org/fork.git').\n * When set, the contributions service fetches the fork's `pullBranch` from this\n * remote (the authoritative committed ref) instead of the local clone, so the\n * comparison no longer depends on the local checkout being up to date. The local\n * clone is still used to read the fork's owned-folder territory when available.\n */\n remoteUrl?: string;\n /** Fork branch that cella pulls contributions from (contributions service) */\n pullBranch: string;\n}\n\n/**\n * User-configurable sync options for cella.config.ts.\n * Simplified for v2 - no long-lived sync branch or squash options.\n */\nexport interface CellaCliConfig {\n /** Core sync settings */\n settings: SyncSettings;\n\n /**\n * File overrides for controlling sync behavior per folder/file.\n */\n overrides?: {\n /**\n * Paths the fork fully owns — never synced (existing or new).\n * Exact paths or directory prefixes, not globs: 'bench' matches 'bench/' and\n * everything under it, 'README.md' matches that exact file.\n * Local territory: upstream cannot add, modify, or delete anything under these.\n */\n ignored?: string[];\n\n /**\n * Paths pinned to fork — fork wins on conflicts.\n * Exact paths or directory prefixes, not globs: 'bench' matches 'bench/' and\n * everything under it, 'README.md' matches that exact file.\n * Non-conflicting upstream changes merge normally.\n * If fork deleted a pinned file, deletion is respected.\n */\n pinned?: string[];\n };\n\n /**\n * Downstream fork repositories that cella interacts with (for upstream template repos).\n * When configured, the 'forks' and 'contributions' services appear in the CLI menu.\n */\n forks?: ForkConfig[];\n}\n\n/**\n * Helper function for defining cella.config.ts with type checking.\n */\nexport function defineConfig(config: CellaCliConfig): CellaCliConfig {\n return config;\n}\n\n/**\n * Strict runtime schema mirroring {@link CellaCliConfig}.\n *\n * The TS interfaces above stay the source of truth (and keep their hover docs for\n * config authors). This schema is what's enforced at load time: `.strict()` rejects\n * unknown keys, so a typo like `ignoredFolders` instead of `ignored` fails closed\n * instead of silently dropping sync protection (tsx does not typecheck the config).\n *\n * The `satisfies z.ZodType<CellaCliConfig>` assertion keeps schema and interface in\n * lockstep: if either drifts (a renamed/removed/mis-typed field), TypeScript errors here.\n */\nexport const cellaConfigSchema = z\n .object({\n settings: z\n .object({\n upstreamUrl: z.string().min(1),\n upstreamBranch: z.string().min(1).optional(),\n upstreamTrack: z.enum(['release', 'branch']).optional(),\n releaseBase: z.string().min(1).optional(),\n packageJsonSync: z\n .array(\n z.enum([\n 'dependencies',\n 'devDependencies',\n 'peerDependencies',\n 'optionalDependencies',\n 'scripts',\n 'engines',\n 'packageManager',\n 'overrides',\n 'pnpm',\n ]),\n )\n .optional(),\n syncWithPackages: z.boolean().optional(),\n fileLinkMode: z.enum(['commit', 'file', 'local']).optional(),\n })\n .strict(),\n overrides: z\n .object({\n ignored: z.array(z.string()).optional(),\n pinned: z.array(z.string()).optional(),\n })\n .strict()\n .optional(),\n forks: z\n .array(\n z\n .object({\n name: z.string().min(1),\n localPath: z.string().min(1),\n remoteUrl: z.string().optional(),\n pullBranch: z.string().min(1),\n })\n .strict(),\n )\n .optional(),\n })\n .strict() satisfies z.ZodType<CellaCliConfig>;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL TYPES - for sync modules\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Sync services available in the CLI */\nexport type SyncService = 'analyze' | 'sync' | 'audit' | 'forks' | 'contributions' | 'stats';\n\n/** Analyze output scope for interactive and machine-readable flows */\nexport type AnalyzeScope = 'all' | 'risk' | 'protected';\n\n/** Runtime configuration with all resolved values */\nexport interface RuntimeConfig extends CellaCliConfig {\n /** Resolved fork repository path */\n forkPath: string;\n\n /** Full upstream remote ref (e.g., 'cella-upstream/development') */\n upstreamRef: string;\n\n /** Selected sync service */\n service: SyncService;\n\n /** Write full file list to log file */\n logFile: boolean;\n\n /** Non-interactive list output (for LLM/agent usage) */\n list: boolean;\n\n /** Machine-readable JSON output (for tooling/agent usage) */\n json: boolean;\n\n /** Print the unified diff for a single contributed file, then exit (contributions; for tooling/agents) */\n diff?: string;\n\n /** Open a browser diff for one file, then exit (analyze) */\n openDiff?: string;\n\n /** Scope of files returned in analyze list/json output */\n scope?: AnalyzeScope;\n\n /** Show verbose output */\n verbose: boolean;\n\n /** Pre-selected fork name (skips fork selection prompt) */\n fork?: string;\n\n /** Overwrite drifted files with upstream version (aggressive realignment) */\n hard?: boolean;\n\n /**\n * Disable pinned entries (cella.config.ts overrides.pinned) for this sync so upstream\n * versions surface as behind/diverged. Managed files stay pinned because cella\n * handles them separately. Like --hard, uses the natural merge-base to resurface\n * full upstream history.\n */\n unpinned?: boolean;\n\n /**\n * Override upstream tracking for this run (analyze/sync), ignoring `settings.upstreamTrack`.\n * 'branch' follows the upstream branch tip (bleeding edge); 'release' uses a release tag.\n */\n track?: 'release' | 'branch';\n\n /** Bypass pnpm metadata cache for fresh registry data (audit service) */\n force?: boolean;\n\n /** Check which pnpm.overrides are still needed (audit service) */\n checkOverrides?: boolean;\n\n /** Regenerate test coverage before showing the stats summary (stats service) */\n coverage?: boolean;\n\n /**\n * After opening the sync PR, enable GitHub auto-merge (squash) so it merges itself once\n * required checks pass (sync service). Opt-in per run via `--direct-merge`; needs auto-merge\n * enabled on the repo. Not the advised default — a sync PR is usually worth a human look.\n */\n directMerge?: boolean;\n}\n\n/** File status after analysis */\nexport type FileStatus =\n | 'identical' // No changes needed\n | 'ahead' // Fork is ahead, protected (pinned/ignored)\n | 'local' // Local file (never existed upstream)\n | 'drifted' // Fork is ahead, NOT protected (at risk)\n | 'behind' // Upstream has changes to sync\n | 'diverged' // Both changed, will merge\n | 'pinned' // Fork wins on conflict\n | 'ignored' // Excluded from sync entirely\n | 'deleted' // Fork deleted, will stay deleted\n | 'renamed'; // Upstream renamed file\n\n/** Analyzed file with status and metadata */\nexport interface AnalyzedFile {\n path: string;\n status: FileStatus;\n /** True if file is in ignored list */\n isIgnored: boolean;\n /** True if file is in pinned list */\n isPinned: boolean;\n /** True if file exists in fork */\n existsInFork: boolean;\n /** True if file exists in upstream */\n existsInUpstream: boolean;\n /** True if file has merge conflict */\n hasConflict?: boolean;\n /** Relative date when file was last changed (since merge-base) */\n changedAt?: string;\n /** Unix epoch seconds of the last change, for sorting */\n changedTs?: number;\n /** Short commit hash of the last change */\n changedCommit?: string;\n /** For diverged files: relative date of upstream change */\n upstreamChangedAt?: string;\n /** For diverged files: Unix epoch seconds of the upstream change, for sorting */\n upstreamChangedTs?: number;\n /** For diverged files: short commit hash of the upstream change */\n upstreamCommit?: string;\n /** For renamed files: the original path before rename */\n renamedFrom?: string;\n}\n\n/** Summary counts by status */\nexport interface AnalysisSummary {\n /** Changed package/config files that are handled separately from normal sync categories */\n managed: number;\n identical: number;\n ahead: number;\n local: number;\n drifted: number;\n behind: number;\n diverged: number;\n pinned: number;\n ignored: number;\n deleted: number;\n renamed: number;\n total: number;\n}\n\n/** Merge result from merge-engine */\nexport interface MergeResult {\n success: boolean;\n /** Upstream branch name for file links */\n upstreamBranch?: string;\n /** Resolved concrete upstream ref that was merged (branch ref or release tag ref) */\n upstreamRef?: string;\n /** Upstream release tag synced (when tracking releases) */\n upstreamTag?: string;\n files: AnalyzedFile[];\n summary: AnalysisSummary;\n conflicts: string[];\n /** Upstream GitHub URL base for commit links */\n upstreamGitHubUrl?: string;\n /** Upstream commit info */\n upstreamCommit?: {\n hash: string;\n message: string;\n date: string;\n };\n /** Commits included in this sync range (oldest-first when rendered) */\n upstreamCommits?: Array<{\n hash: string;\n message: string;\n date: string;\n }>;\n /** Files that were auto-merged by git (diverged without remaining conflicts) */\n autoMergedFiles?: string[];\n}\n","/**\n * Static analysis of module ownership for sync CLI.\n *\n * Each module declares ownership via a `registerModule({ owner, ... })` call in\n * its `*-module.ts` file. Modules with `owner: 'app'` are fork-specific: their\n * source folders, plus matching frontend static asset folders when present, are\n * fork territory and must never be added, modified, or deleted by upstream during\n * sync — nor offered back upstream by the contributions service.\n *\n * Parsing is syntax-only (no type-checker), so it is fast and tolerant of\n * formatting, comments, and property order. Built on ts-morph so the same\n * project/AST approach can be reused for other source-introspection tasks.\n */\n\nimport { existsSync } from 'node:fs';\nimport { basename, join, relative, sep } from 'node:path';\nimport { Project, SyntaxKind } from 'ts-morph';\n\n/** Glob patterns (relative to repo root) for module definition files. */\nconst MODULE_FILE_GLOBS = ['backend/src/modules/*/*-module.ts', 'frontend/src/modules/*/*-module.ts'];\nconst FRONTEND_STATIC_ROOT = 'frontend/public/static';\n\n/**\n * Read the string value of an object literal's `owner` property, if present.\n */\nfunction readOwner(call: import('ts-morph').CallExpression): string | undefined {\n const arg = call.getArguments()[0]?.asKind(SyntaxKind.ObjectLiteralExpression);\n const initializer = arg?.getProperty('owner')?.asKind(SyntaxKind.PropertyAssignment)?.getInitializer();\n return initializer?.asKind(SyntaxKind.StringLiteral)?.getLiteralValue();\n}\n\n/**\n * Scan a repository for module territory owned by the app (`owner: 'app'`).\n *\n * @param repoPath - Absolute path to the repository root to scan.\n * @returns Repo-relative folder paths (POSIX separators), deduplicated.\n */\nexport function resolveAppModuleFolders(repoPath: string): string[] {\n const project = new Project({\n skipAddingFilesFromTsConfig: true,\n skipFileDependencyResolution: true,\n skipLoadingLibFiles: true,\n });\n\n const sourceFiles = project.addSourceFilesAtPaths(MODULE_FILE_GLOBS.map((glob) => `${repoPath}/${glob}`));\n\n const folders = new Set<string>();\n const moduleNames = new Set<string>();\n\n for (const sourceFile of sourceFiles) {\n const ownsApp = sourceFile\n .getDescendantsOfKind(SyntaxKind.CallExpression)\n .some((call) => call.getExpression().getText() === 'registerModule' && readOwner(call) === 'app');\n\n if (!ownsApp) continue;\n\n const folder = relative(repoPath, sourceFile.getDirectoryPath()).split(sep).join('/');\n folders.add(folder);\n moduleNames.add(basename(folder));\n }\n\n for (const moduleName of moduleNames) {\n const staticFolder = `${FRONTEND_STATIC_ROOT}/${moduleName}`;\n if (existsSync(join(repoPath, staticFolder))) {\n folders.add(staticFolder);\n }\n }\n\n return [...folders];\n}\n","/**\n * Display utilities for sync CLI v2.\n *\n * Handles console output formatting, progress tracking, and result display.\n */\n\nimport { writeFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport process from 'node:process';\nimport packageJson from '../../package.json' with { type: 'json' };\nimport type { AnalysisSummary, AnalyzedFile, FileStatus, MergeResult } from '../config/types';\nimport pc from './colors';\nimport { getEnv } from './env';\nimport { isManagedFile } from './managed-files';\n\n/** CLI name */\nexport const NAME = 'cella cli';\n\n/** Version from package.json */\nexport const VERSION = packageJson.version;\n\n/** Options for generating links in CLI output */\nexport interface LinkOptions {\n /** Base GitHub URL for upstream (e.g., 'https://github.com/cellajs/cella') */\n upstreamGitHubUrl?: string;\n /** Upstream branch name for file links */\n upstreamBranch?: string;\n /** File link mode: 'commit' links to commit, 'file' links to file in repo ('local' is deprecated, treated as 'file') */\n fileLinkMode?: 'commit' | 'file' | 'local';\n /** Fork repository path for resolving file paths */\n forkPath?: string;\n}\n\n/** Line divider */\nexport const DIVIDER = '─'.repeat(60);\n\n/** Warning mark for non-fatal warnings */\nexport const warningMark = pc.yellow('⚠');\n\n/** Check mark for successful status lines */\nexport const checkMark = pc.green('✓');\n\ninterface Spinner {\n text: string;\n start(): Spinner;\n stop(): void;\n}\n\nclass TerminalSpinner implements Spinner {\n private readonly frames = ['-', '\\\\', '|', '/'];\n private frameIndex = 0;\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly enabled: boolean;\n\n constructor(\n public text: string,\n isSilent: boolean,\n ) {\n this.enabled = !isSilent && !!process.stdout.isTTY;\n }\n\n start(): Spinner {\n if (!this.enabled || this.timer) return this;\n\n this.render();\n this.timer = setInterval(() => {\n this.frameIndex = (this.frameIndex + 1) % this.frames.length;\n this.render();\n }, 80);\n\n return this;\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n\n if (!this.enabled) return;\n\n process.stdout.write('\\r\\x1b[2K');\n }\n\n private render(): void {\n process.stdout.write(`\\r${pc.cyan(this.frames[this.frameIndex])} ${this.text}`);\n }\n}\n\n/** Active spinner reference */\nlet activeSpinner: Spinner | null = null;\n\n/**\n * When true, stdout is reserved for machine-readable payloads (e.g. `--json`),\n * so all human-facing output (header, warnings, steps, spinner) is routed to stderr.\n */\nlet jsonMode = false;\n\n/**\n * Enable JSON mode: keep stdout clean for the JSON payload by sending every\n * human-facing line (console.info/console.warn, header, spinner) to stderr.\n * This makes `cella --json ... | jq` pipe cleanly.\n */\nexport function setJsonMode(enabled: boolean): void {\n jsonMode = enabled;\n if (!enabled) return;\n const toStderr = (...args: unknown[]) => {\n process.stderr.write(`${args.map((a) => (typeof a === 'string' ? a : String(a))).join(' ')}\\n`);\n };\n console.info = toStderr;\n console.log = toStderr;\n console.warn = toStderr;\n}\n\n/** Write a machine-readable payload to stdout (bypasses the stderr routing of JSON mode). */\nexport function writeStdout(text: string): void {\n process.stdout.write(text.endsWith('\\n') ? text : `${text}\\n`);\n}\n\n/**\n * Get the header line for CLI output.\n */\nfunction getHeader(): string {\n const right = 'cellajs.com';\n // Account for ANSI codes when calculating padding\n const visibleLeft = `⧈ ${NAME} v${VERSION}`;\n const padding = Math.max(1, 60 - visibleLeft.length - right.length);\n return `${pc.cyan(`⧈ ${NAME}`)}${pc.dim(` · v${VERSION}`)}${pc.cyan(`${' '.repeat(padding)}${right}`)}`;\n}\n\n/**\n * Print the welcome header.\n */\nexport function printHeader(): void {\n console.info();\n console.info(getHeader());\n console.info(DIVIDER);\n console.info();\n}\n\n/**\n * Print a completed step with checkmark.\n * Optionally include a detail line in grey, followed by a blank line.\n */\nfunction printStep(label: string, detail?: string): void {\n console.info(`${checkMark} ${label}`);\n if (detail) {\n console.info(` ${pc.dim(detail)}`);\n console.info(); // blank line after detail block\n }\n}\n\n/**\n * Create a progress spinner.\n * Uses isSilent in test environments to suppress output.\n */\nexport function createSpinner(text: string): Spinner {\n const isTestEnv = !!getEnv('VITEST') || getEnv('NODE_ENV') === 'test';\n activeSpinner = new TerminalSpinner(text, isTestEnv || jsonMode);\n activeSpinner.start();\n return activeSpinner;\n}\n\n/**\n * Stop the active spinner with success and print step.\n */\nexport function spinnerSuccess(message?: string, detail?: string): void {\n stopSpinner();\n if (message) {\n printStep(message, detail);\n }\n}\n\n/**\n * Stop the active spinner with failure.\n */\nexport function spinnerFail(message: string): void {\n stopSpinner();\n console.info(`${pc.red('✗')} ${message}`);\n}\n\n/**\n * Update spinner text.\n */\nexport function spinnerText(text: string): void {\n if (activeSpinner) {\n activeSpinner.text = text;\n }\n}\n\n/**\n * Stop and clear the active spinner.\n */\nfunction stopSpinner(): void {\n if (activeSpinner) {\n activeSpinner.stop();\n activeSpinner = null;\n }\n}\n\n/**\n * Create a clickable hyperlink for terminals that support OSC 8.\n * Falls back to just the label if no URL provided.\n */\nexport function hyperlink(label: string, url?: string): string {\n if (!url) return label;\n // Strip control characters from URL to prevent terminal escape injection (CWE-116)\n // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping control chars is the security purpose here.\n const safeUrl = url.replace(/[\\x00-\\x1f\\x7f]/g, '');\n // OSC 8 hyperlink format: \\x1b]8;;URL\\x07LABEL\\x1b]8;;\\x07\n return `\\x1b]8;;${safeUrl}\\x07${label}\\x1b]8;;\\x07`;\n}\n\n/**\n * Build a VS Code deep link that opens a file from the fork workspace.\n */\nfunction getVsCodeOpenFileLink(filePath: string, options: LinkOptions): string {\n const { forkPath } = options;\n if (!forkPath) return filePath;\n\n const absolutePath = resolve(forkPath, filePath);\n const url = `vscode://file${absolutePath}`;\n return hyperlink(filePath, url);\n}\n\n/** Commit info used for sync progress output */\nexport interface SyncCommitInfo {\n hash: string;\n message: string;\n date: string;\n}\n\n/**\n * Format the fetched-upstream detail block with clickable short commit hashes.\n */\nexport function formatFetchedUpstreamDetail(\n commitCount: number,\n commits: SyncCommitInfo[],\n upstreamGitHubUrl?: string,\n maxShownCommits = 50,\n): string {\n const commitLabel = commitCount === 1 ? '1 new commit' : `${commitCount} new commits`;\n const lines = [`${commitLabel} since last merge`];\n\n const shown = commits.slice(0, maxShownCommits);\n for (const commit of shown) {\n const shortHash = commit.hash.slice(0, 7);\n const commitUrl = upstreamGitHubUrl ? `${upstreamGitHubUrl}/commit/${commit.hash}` : undefined;\n const hashLabel = hyperlink(shortHash, commitUrl);\n lines.push(` ${hashLabel} \"${commit.message}\" (${commit.date})`);\n }\n\n if (commitCount > shown.length) {\n lines.push(` ... and ${commitCount - shown.length} more`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Generate a link for a file based on link style.\n * Returns { label, url } for use with hyperlink().\n */\nfunction getFileLink(\n filePath: string,\n commitHash: string | undefined,\n options: LinkOptions,\n): { label: string; url?: string } {\n const { upstreamGitHubUrl, upstreamBranch, fileLinkMode = 'commit' } = options;\n // 'local' linked into the upstream view worktree before browser diffs replaced it.\n const mode = fileLinkMode === 'local' ? 'file' : fileLinkMode;\n\n if (!upstreamGitHubUrl) {\n return { label: commitHash?.slice(0, 9) || '' };\n }\n\n if (mode === 'file' && upstreamBranch) {\n // Link to file in repo: https://github.com/org/repo/blob/branch/path/to/file\n const url = `${upstreamGitHubUrl}/blob/${upstreamBranch}/${filePath}`;\n return { label: filePath.split('/').pop() || filePath, url };\n }\n\n // Default: link to commit\n if (commitHash) {\n const url = `${upstreamGitHubUrl}/commit/${commitHash}`;\n return { label: commitHash.slice(0, 9), url };\n }\n\n return { label: '' };\n}\n\n/**\n * Print a section header with title and divider.\n */\nfunction printSectionHeader(title: string): void {\n console.info();\n console.info(title);\n console.info(DIVIDER);\n console.info();\n}\n\n/**\n * Format file date info with link for display.\n */\nfunction formatFileDateInfo(\n filePath: string,\n commit: string | undefined,\n date: string | undefined,\n linkOptions: LinkOptions,\n): string {\n const link = getFileLink(filePath, commit, linkOptions);\n const linkLabel = link.label ? hyperlink(link.label, link.url) : '';\n return date ? pc.dim(` ≠ ${date} ${linkLabel}`) : '';\n}\n\n/**\n * Format merge-in-progress detail with conflicts and auto-merged file links.\n */\nexport function formatMergeInProgressDetail(\n conflictCount: number,\n autoMergedFiles: string[],\n linkOptions: LinkOptions,\n maxFiles = 100,\n): string {\n const lines = [`${conflictCount} conflicts to resolve in IDE`];\n\n if (autoMergedFiles.length === 0) {\n return lines.join('\\n');\n }\n\n lines.push('');\n lines.push(` auto-merged files (${autoMergedFiles.length}):`);\n\n const shown = autoMergedFiles.slice(0, maxFiles);\n for (const filePath of shown) {\n const fileLink = getVsCodeOpenFileLink(filePath, linkOptions);\n lines.push(` - ${fileLink}`);\n }\n\n if (autoMergedFiles.length > shown.length) {\n lines.push(` ... + ${autoMergedFiles.length - shown.length} more`);\n }\n\n return lines.join('\\n');\n}\n\n/** Display configuration for a file status */\ninterface StatusConfig {\n icon: string;\n label: string;\n color: (text: string) => string;\n description?: string;\n}\n\ntype SummaryStatus = FileStatus | 'managed';\n\n/** Unified status display config: icon, label, color, and description for each status. Key order defines sort priority. */\nconst statusConfig: Record<FileStatus, StatusConfig> = {\n behind: { icon: pc.cyan('↓'), label: 'behind', color: pc.cyan, description: 'upstream changed, will sync' },\n diverged: { icon: pc.magenta('⇅'), label: 'diverged', color: pc.magenta, description: 'both changed, will merge' },\n drifted: { icon: pc.yellow('!'), label: 'drifted', color: pc.yellow, description: 'fork changed (at risk)' },\n ahead: { icon: pc.blue('↑'), label: 'ahead', color: pc.blue, description: 'fork changed (protected)' },\n local: { icon: pc.green('+'), label: 'local', color: pc.green, description: 'local file' },\n pinned: { icon: pc.green('⨀'), label: 'pinned', color: pc.green, description: 'both changed, fork wins' },\n ignored: { icon: pc.gray('⨂'), label: 'ignored', color: pc.gray },\n identical: { icon: pc.gray('✓'), label: 'identical', color: pc.gray, description: 'no changes' },\n deleted: { icon: pc.red('✗'), label: 'deleted', color: pc.red },\n renamed: { icon: pc.blue('→'), label: 'renamed', color: pc.blue },\n};\n\nconst summaryStatusConfig: Record<SummaryStatus, StatusConfig> = {\n ...statusConfig,\n managed: {\n icon: pc.cyan('◇'),\n label: 'managed',\n color: pc.cyan,\n description: 'package.jsons & cella.config.ts handled separately',\n },\n ignored: { ...statusConfig.ignored, description: 'protected by ignored config' },\n};\n\n/** Ordered status keys derived from statusConfig key order */\nconst statusOrder = Object.keys(statusConfig) as FileStatus[];\n\n/**\n * Print the analysis summary.\n */\nexport function printSummary(summary: AnalysisSummary, title = 'summary'): void {\n printSectionHeader(pc.cyan(title));\n\n // Format counts with padding.\n const maxCount = Math.max(\n summary.managed,\n summary.ignored,\n summary.identical,\n summary.ahead,\n summary.local,\n summary.drifted,\n summary.behind,\n summary.diverged,\n summary.pinned,\n summary.deleted,\n summary.renamed,\n );\n const countWidth = String(maxCount).length + 1;\n\n // Helper to print a status line using unified config\n const printLine = (status: SummaryStatus, count: number) => {\n const { icon, label, color, description } = summaryStatusConfig[status];\n const countStr = color(String(count).padStart(countWidth));\n const desc = description ? pc.dim(description) : '';\n console.info(` ${icon} ${countStr} ${label.padEnd(15)}${desc}`);\n };\n\n // Grouped layout with blank lines between groups\n printLine('managed', summary.managed);\n printLine('ignored', summary.ignored);\n\n console.info();\n printLine('identical', summary.identical);\n\n console.info();\n printLine('ahead', summary.ahead);\n printLine('local', summary.local);\n printLine('drifted', summary.drifted);\n\n console.info();\n printLine('diverged', summary.diverged);\n printLine('pinned', summary.pinned);\n\n console.info();\n printLine('behind', summary.behind);\n}\n\n/**\n * Print a group of files with a specific status, including section header and footer.\n */\nfunction printFileGroup(\n files: AnalyzedFile[],\n status: FileStatus,\n linkOptions: LinkOptions,\n options?: {\n /** Override section header title */\n title?: string;\n /** Footer hint text (dimmed) */\n hint?: string;\n /** Which commit/date fields to use: 'fork' or 'upstream' */\n dateSource?: 'fork' | 'upstream';\n },\n): void {\n const filtered = files.filter((f) => f.status === status && !isManagedFile(f.path));\n if (filtered.length === 0) return;\n\n const config = statusConfig[status];\n const title = options?.title ?? `${config.icon} ${config.label}`;\n\n printSectionHeader(`${title} ${pc.dim(`· ${filtered.length} files`)}`);\n\n const useUpstream = options?.dateSource === 'upstream';\n const maxLines = 100;\n const shown = filtered.length > maxLines ? filtered.slice(0, maxLines) : filtered;\n\n for (const file of shown) {\n const commit = useUpstream ? file.upstreamCommit : file.changedCommit;\n const date = useUpstream ? file.upstreamChangedAt : file.changedAt;\n const dateInfo = formatFileDateInfo(file.path, commit, date, linkOptions);\n console.info(` ${config.icon} ${file.path}${dateInfo}`);\n }\n\n if (filtered.length > maxLines) {\n console.info(pc.dim(` ... + ${filtered.length - maxLines} more`));\n }\n\n if (options?.hint) {\n console.info();\n console.info(pc.dim(` ${options.hint}`));\n }\n}\n\n/**\n * Print all analyze-mode file group sections in review order:\n * behind, ahead (protected), drifted, diverged, and pinned.\n */\nexport function printAnalysisFileGroups(files: AnalyzedFile[], linkOptions: LinkOptions): void {\n printFileGroup(files, 'behind', linkOptions, {\n title: pc.cyan('↓ behind on upstream'),\n });\n printFileGroup(files, 'ahead', linkOptions, {\n title: `${pc.blue('↑ protected in fork')}`,\n hint: 'these files have fork changes and are protected by pinned or ignored config.',\n });\n printFileGroup(files, 'drifted', linkOptions, {\n title: `${warningMark} ${pc.yellow('drifted from upstream')}`,\n hint: 'these files have fork changes but are not pinned or ignored.',\n });\n printFileGroup(files, 'diverged', linkOptions, {\n title: `${pc.magenta('⇅ diverged')}`,\n hint: 'both fork and upstream changed.',\n dateSource: 'upstream',\n });\n printFileGroup(files, 'pinned', linkOptions, {\n title: `${pc.green('⨀ pinned')}`,\n hint: 'both changed, fork wins (pinned in cella.config.ts).',\n dateSource: 'upstream',\n });\n}\n\n/**\n * Write full file list to log file.\n */\nexport function writeLogFile(forkPath: string, files: AnalyzedFile[]): string {\n const logPath = join(forkPath, 'cella-sync.log');\n\n const lines: string[] = [\n `cella sync analysis - ${new Date().toISOString()}`,\n DIVIDER,\n '',\n `complete file list (${files.length} files)`,\n DIVIDER,\n '',\n ];\n\n // Sort files by status, then path\n const sortedFiles = [...files].sort((a, b) => {\n const aOrder = statusOrder.indexOf(a.status);\n const bOrder = statusOrder.indexOf(b.status);\n if (aOrder !== bOrder) return aOrder - bOrder;\n return a.path.localeCompare(b.path);\n });\n\n for (const file of sortedFiles) {\n const config = statusConfig[file.status];\n // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping ANSI escape sequences requires \\x1b literal.\n const icon = config.icon.replace(/\\x1b\\[[0-9;]*m/g, ''); // Strip ANSI\n lines.push(` ${icon} ${config.label.padEnd(12)} ${file.path}`);\n }\n\n writeFileSync(logPath, lines.join('\\n'), 'utf-8');\n return logPath;\n}\n\n/**\n * Print sync completion message.\n */\nexport function printSyncComplete(result: MergeResult, options: { stagedBranch?: string } = {}): void {\n const updated = result.files.filter((file) => file.status === 'behind' || file.status === 'diverged').length;\n const diverged = result.files.filter((file) => file.status === 'diverged').length;\n const merged = result.autoMergedFiles?.length ?? Math.max(0, diverged - result.conflicts.length);\n const conflicts = result.conflicts.length;\n\n console.info();\n if (options.stagedBranch) {\n console.info(`${pc.green('✓')} Sync merge staged on '${options.stagedBranch}'`);\n console.info(\n pc.dim(\n ` ${updated} files updated, ${merged} auto-merged, ${conflicts} conflicts. Review, then rerun \\`pnpm cella sync\\` to finish.`,\n ),\n );\n } else {\n console.info(`${pc.green('✓')} sync complete`);\n console.info(pc.dim(` ${updated} files updated, ${merged} auto-merged, ${conflicts} conflicts`));\n }\n\n console.info();\n}\n\n/**\n * Print warnings for aggressive sync flags (--hard / --unpinned) after completion.\n *\n * Explains what each active flag did and its consequence, and adds a shared\n * caution to cherry-pick deliberately when either is used.\n */\nexport function printFlagWarnings(options: { hard?: boolean; unpinned?: boolean }): void {\n const { hard, unpinned } = options;\n if (!hard && !unpinned) return;\n\n if (hard) {\n console.info(pc.yellow('⚠ --hard used: drifted files were treated as behind, overwriting with incoming.'));\n }\n if (unpinned) {\n console.info(\n pc.yellow('⚠ --unpinned used: pinned files in cella.config.ts were ignored, this can result in more drifts.'),\n );\n }\n console.info(pc.yellow(' Be extra careful & cherrypick what you want only.'));\n console.info();\n}\n","{\n \"name\": \"@cellajs/cli\",\n \"version\": \"0.0.6\",\n \"private\": false,\n \"license\": \"MIT\",\n \"description\": \"CLI for managing your monorepo and syncing with upstream Cella.\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/cellajs/cella-cli\"\n },\n \"homepage\": \"https://cellajs.com\",\n \"author\": \"CellaJS <info@cellajs.com>\",\n \"engines\": {\n \"node\": \"24.x\"\n },\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"exports\": {\n \".\": \"./dist/index.js\",\n \"./config\": {\n \"types\": \"./dist/config.d.ts\",\n \"import\": \"./dist/config.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\",\n \"index.js\",\n \"README.md\"\n ],\n \"bin\": {\n \"cella\": \"index.js\"\n },\n \"imports\": {\n \"#/*\": \"./src/*\"\n },\n \"scripts\": {\n \"start\": \"tsx index.ts\",\n \"clean\": \"rimraf ./dist\",\n \"build\": \"tsup\",\n \"test-build\": \"pnpm run build && node index.js --help\",\n \"prepublishOnly\": \"pnpm run test:release\",\n \"check\": \"pnpm ts && pnpm biome check --write .\",\n \"ts\": \"tsgo --pretty\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"test\": \"vitest run\",\n \"test:release\": \"pnpm run build && vitest run --config vitest.release.config.ts\",\n \"test:watch\": \"vitest\",\n \"prepare\": \"lefthook install\"\n },\n \"dependencies\": {\n \"@inquirer/core\": \"^11.2.1\",\n \"@inquirer/prompts\": \"^8.5.2\",\n \"@pierre/diffs\": \"^1.2.12\",\n \"commander\": \"^15.0.0\",\n \"ts-morph\": \"^28.0.0\",\n \"zod\": \"^4.4.3\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.5.2\",\n \"@commitlint/cli\": \"^21.2.0\",\n \"@commitlint/config-conventional\": \"^21.2.0\",\n \"@evilmartians/lefthook\": \"^2.1.9\",\n \"@types/node\": \"24.10.13\",\n \"@typescript/native-preview\": \"7.0.0-dev.20260702.3\",\n \"rimraf\": \"^6.1.3\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.22.4\",\n \"typescript\": \"^6.0.3\",\n \"vitest\": \"^4.1.9\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"keywords\": [\n \"cella\",\n \"cellajs\",\n \"cli\",\n \"sync\",\n \"template\"\n ],\n \"packageManager\": \"pnpm@11.8.0\",\n \"commitlint\": {\n \"extends\": [\n \"@commitlint/config-conventional\"\n ],\n \"rules\": {\n \"type-enum\": [\n 2,\n \"always\",\n [\n \"feat\",\n \"fix\",\n \"perf\",\n \"refactor\",\n \"revert\",\n \"docs\",\n \"chore\",\n \"build\",\n \"ci\",\n \"style\",\n \"test\"\n ]\n ],\n \"header-max-length\": [\n 2,\n \"always\",\n 120\n ],\n \"body-max-line-length\": [\n 0,\n \"always\",\n 200\n ],\n \"footer-max-line-length\": [\n 0,\n \"always\",\n 200\n ]\n }\n }\n}\n","/**\n * Files that cella manages outside the normal file sync categories.\n */\n\n/**\n * Check if a file path is a package.json file.\n */\nexport function isPackageJson(filePath: string): boolean {\n return filePath === 'package.json' || filePath.endsWith('/package.json');\n}\n\n/**\n * Check if a file path is managed by cella outside normal file sync categories.\n */\nexport function isManagedFile(filePath: string): boolean {\n return isPackageJson(filePath) || filePath === 'pnpm-lock.yaml' || filePath === 'cella.config.ts';\n}\n","/**\n * Override matching and validation utilities for sync CLI v2.\n *\n * Handles matching files against ignored/pinned paths and\n * validates config for potential issues.\n */\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { CellaCliConfig } from '../config/types';\nimport { warningMark } from './display';\nimport { isManagedFile } from './managed-files';\n\n/**\n * Check if a file path is owned by any of the given folders.\n *\n * Folders are directory prefixes (not globs): an entry matches the file when\n * the path equals the entry exactly or is nested under `entry + '/'`.\n *\n * @param filePath - The file path to test\n * @param folders - Folder prefixes (or exact paths) to match against\n */\nexport function isUnderAnyFolder(filePath: string, folders: string[]): boolean {\n return folders.some((folder) => {\n const entry = folder.replace(/\\/+$/, '');\n return filePath === entry || filePath.startsWith(`${entry}/`);\n });\n}\n\n/**\n * Check if a file is inside an ignored path.\n */\nexport function isIgnored(filePath: string, config: CellaCliConfig): boolean {\n return isUnderAnyFolder(filePath, config.overrides?.ignored || []);\n}\n\n/**\n * Check if a file is in the pinned list.\n * Managed files are always considered pinned (handled separately by cella).\n */\nexport function isPinned(filePath: string, config: CellaCliConfig): boolean {\n if (isManagedFile(filePath)) return true;\n return isUnderAnyFolder(filePath, config.overrides?.pinned || []);\n}\n\n/**\n * Resolve effective pin status for a sync run, honoring the --unpinned flag.\n *\n * When `unpinned` is true, configured pins are disabled so upstream versions\n * surface as behind/diverged — but managed files stay pinned (their content is\n * reconciled separately by cella).\n */\nexport function isPinnedForSync(filePath: string, config: CellaCliConfig, unpinned?: boolean): boolean {\n if (isManagedFile(filePath)) return true;\n if (unpinned) return false;\n return isPinned(filePath, config);\n}\n\n/** Validation warning */\ninterface ConfigWarning {\n type: 'pinned-glob' | 'pinned-not-found' | 'ignored-not-found';\n pattern: string;\n message: string;\n}\n\n/**\n * Check if an entry contains glob characters (no longer supported).\n */\nfunction hasGlobChars(entry: string): boolean {\n return entry.includes('*') || entry.includes('?');\n}\n\n/**\n * Validate config overrides and return warnings.\n *\n * Checks for:\n * - Pinned entries using glob patterns (no longer supported)\n * - Pinned entries that don't exist in fork\n * - Ignored entries that don't exist in fork\n *\n * @param config - The sync config to validate\n * @param forkPath - Path to the fork repository\n */\nexport function validateOverrides(config: CellaCliConfig, forkPath: string): ConfigWarning[] {\n const warnings: ConfigWarning[] = [];\n\n // Check pinned entries\n const pinned = config.overrides?.pinned || [];\n for (const entry of pinned) {\n if (hasGlobChars(entry)) {\n warnings.push({\n type: 'pinned-glob',\n pattern: entry,\n message: `pin uses glob (not supported, use a path or folder): ${entry}`,\n });\n } else if (!existsSync(join(forkPath, entry))) {\n warnings.push({\n type: 'pinned-not-found',\n pattern: entry,\n message: `pin not found: ${entry}`,\n });\n }\n }\n\n // Check ignored entries\n const ignored = config.overrides?.ignored || [];\n for (const entry of ignored) {\n if (hasGlobChars(entry)) {\n warnings.push({\n type: 'ignored-not-found',\n pattern: entry,\n message: `ignored entry uses glob (not supported, use a path or folder): ${entry}`,\n });\n } else if (!existsSync(join(forkPath, entry.replace(/\\/+$/, '')))) {\n warnings.push({\n type: 'ignored-not-found',\n pattern: entry,\n message: `ignored entry not found: ${entry}`,\n });\n }\n }\n\n return warnings;\n}\n\n/**\n * Print validation warnings to console.\n */\nexport function printWarnings(warnings: ConfigWarning[]): void {\n for (const warning of warnings) {\n console.info(`${warningMark} ${warning.message}`);\n }\n}\n","/**\n * Analyze service for sync CLI v2.\n *\n * Dry run of sync - shows what would change without applying.\n * Uses the same merge-engine as sync, but discards the result.\n */\n\nimport { basename } from 'node:path';\nimport type { MergeResult, RuntimeConfig } from '../config/types';\nimport pc from '../utils/colors';\nimport { gitDiffFile, openDiffInBrowser } from '../utils/diff';\nimport {\n createSpinner,\n type LinkOptions,\n printAnalysisFileGroups,\n printSummary,\n spinnerSuccess,\n spinnerText,\n writeLogFile,\n writeStdout,\n} from '../utils/display';\nimport { runMergeEngine } from './merge-engine';\n\nconst scopeStatuses: Record<'all' | 'risk' | 'protected', Set<string>> = {\n all: new Set(['ahead', 'drifted', 'diverged']),\n risk: new Set(['drifted', 'diverged']),\n protected: new Set(['ahead']),\n};\n\nfunction filterByScope(files: MergeResult['files'], scope: 'all' | 'risk' | 'protected'): MergeResult['files'] {\n const statuses = scopeStatuses[scope];\n return files.filter((f) => statuses.has(f.status));\n}\n\nfunction findTargetFile(files: MergeResult['files'], targetPath: string) {\n const exact = files.find((f) => f.path === targetPath);\n if (exact) return exact;\n\n const normalized = targetPath.replace(/^\\.\\//, '');\n return files.find((f) => f.path === normalized);\n}\n\nfunction printUnifiedDiff(config: RuntimeConfig, filePath: string): void {\n // Label the upstream side 'cella/' and the local side with the repo's folder name\n // so the diff reads cella/<path> vs <fork>/<path> instead of opaque a/ and b/.\n const diff = gitDiffFile(config.forkPath, `${config.upstreamRef}..HEAD`, filePath, {\n dstPrefix: basename(config.forkPath),\n });\n writeStdout(diff.toString());\n}\n\n/**\n * Run the analyze service (dry run).\n *\n * Creates worktree, performs merge, shows results, discards worktree.\n */\nexport async function runAnalyze(config: RuntimeConfig): Promise<MergeResult> {\n createSpinner('starting analysis...');\n\n const result = await runMergeEngine(config, {\n apply: false,\n onProgress: (message) => {\n spinnerText(message);\n },\n onStep: (label, detail) => {\n spinnerSuccess(label, detail);\n createSpinner('...');\n },\n });\n\n spinnerSuccess();\n\n const scopedFiles = filterByScope(result.files, config.scope ?? 'all');\n\n if (config.diff) {\n const file = findTargetFile(scopedFiles, config.diff) ?? findTargetFile(result.files, config.diff);\n if (!file) throw new Error(`file not found in analysis results: ${config.diff}`);\n printUnifiedDiff(config, file.path);\n return result;\n }\n\n if (config.json) {\n const out = scopedFiles.map((f) => ({\n path: f.path,\n status: f.status,\n changedAt: f.changedAt ?? null,\n changedCommit: f.changedCommit ?? null,\n upstreamChangedAt: f.upstreamChangedAt ?? null,\n upstreamCommit: f.upstreamCommit ?? null,\n }));\n writeStdout(JSON.stringify(out, null, 2));\n return result;\n }\n\n if (config.list) {\n for (const file of scopedFiles) {\n console.info(file.path);\n }\n return result;\n }\n\n if (config.openDiff) {\n const file = findTargetFile(scopedFiles, config.openDiff) ?? findTargetFile(result.files, config.openDiff);\n if (!file) throw new Error(`file not found in analysis results: ${config.openDiff}`);\n\n // Diff the upstream ref against the working tree (single ref, no range) so\n // the rendered page includes uncommitted local changes — the same live view\n // the old VS Code diff gave.\n const patch = gitDiffFile(config.forkPath, config.upstreamRef, file.path);\n if (patch.length === 0) {\n console.info(`${pc.green('✓')} ${file.path} is identical to upstream`);\n return result;\n }\n\n const pagePath = await openDiffInBrowser(\n patch.toString(),\n {\n filePath: file.path,\n srcLabel: 'cella',\n dstLabel: basename(config.forkPath),\n note: 'local working tree',\n },\n config.forkPath,\n );\n console.info(`${pc.green('✓')} opened browser diff for ${file.path}`);\n console.info(pc.dim(` ${pagePath}`));\n return result;\n }\n\n // Build link options from result and config\n const linkOptions: LinkOptions = {\n upstreamGitHubUrl: result.upstreamGitHubUrl,\n upstreamBranch: result.upstreamBranch,\n fileLinkMode: config.settings.fileLinkMode,\n forkPath: config.forkPath,\n };\n\n // Print file lists first (analyze shows file lists for review)\n printAnalysisFileGroups(result.files, linkOptions);\n\n // Print summary at the end\n printSummary(result.summary, 'analysis summary');\n\n // Write log file if requested\n if (config.logFile) {\n const logPath = writeLogFile(config.forkPath, result.files);\n console.info();\n console.info(pc.dim(`full file list written to: ${logPath}`));\n }\n\n console.info();\n\n return result;\n}\n","/**\n * Diff helpers for sync CLI v2.\n *\n * Shared logic for producing a single-file `git diff` and for rendering a diff\n * as a self-contained HTML page that opens in the default browser. Used by the\n * analyze and contributions services.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { basename, join } from 'node:path';\nimport process from 'node:process';\n\n/**\n * Run `git diff` for a single file.\n *\n * With `dstPrefix`, the sides are labeled `cella/<path>` vs `<dstPrefix>/<path>`\n * instead of opaque a/ and b/ — used for the `--diff` stdout mode where the\n * labels carry meaning. Without it, standard a/ b/ prefixes are kept, which the\n * HTML renderer's patch parser requires.\n *\n * @param cwd - Repo to run the diff in\n * @param range - Ref range (e.g. 'upstreamRef..HEAD'), or a single ref to diff\n * that ref against the working tree\n * @param filePath - File to diff\n * @returns Raw diff output (empty when the file is identical)\n */\nexport function gitDiffFile(\n cwd: string,\n range: string,\n filePath: string,\n options: { dstPrefix?: string } = {},\n): Buffer {\n const args = ['diff', '--no-color'];\n if (options.dstPrefix) args.push('--src-prefix=cella/', `--dst-prefix=${options.dstPrefix}/`);\n args.push(range, '--', filePath);\n\n try {\n return execFileSync('git', args, { cwd, maxBuffer: 50 * 1024 * 1024 });\n } catch (error) {\n const stderr = (error as { stderr?: Buffer }).stderr?.toString().trim();\n throw new Error(stderr || `failed to diff ${filePath}`);\n }\n}\n\n/** Labels shown in the header of a rendered diff page. */\nexport interface DiffPageMeta {\n /** File path shown in the page header and title */\n filePath: string;\n /** Label for the upstream side (e.g. 'cella') */\n srcLabel: string;\n /** Label for the local side (e.g. the fork name) */\n dstLabel: string;\n /** Extra context shown after the labels (e.g. 'includes uncommitted changes') */\n note?: string;\n}\n\nfunction escapeHtml(text: string): string {\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n}\n\n/**\n * Render a unified diff as a complete, self-contained HTML document.\n *\n * Highlighting and diff layout come from `@pierre/diffs` (Shiki-based), rendered\n * server-side to static HTML: no scripts, no external requests, adapts to the\n * viewer's light/dark preference. The patch must use standard a/ b/ prefixes\n * (call `gitDiffFile` without `dstPrefix`); side labels belong in `meta` instead.\n */\nexport async function renderDiffPage(patch: string, meta: DiffPageMeta): Promise<string> {\n // Lazy import: the CLI is a short-lived process and most invocations never\n // render a diff, so startup shouldn't pay Shiki's module-load cost.\n const { preloadPatchDiff } = await import('@pierre/diffs/ssr');\n\n const { prerenderedHTML } = await preloadPatchDiff({\n patch,\n options: {\n diffStyle: 'split',\n themeType: 'system',\n lineDiffType: 'word-alt',\n hunkSeparators: 'line-info',\n overflow: 'wrap',\n disableFileHeader: true,\n },\n });\n\n const title = `${escapeHtml(meta.filePath)} · ${escapeHtml(meta.srcLabel)} vs ${escapeHtml(meta.dstLabel)}`;\n const note = meta.note ? `<span class=\"note\">· ${escapeHtml(meta.note)}</span>` : '';\n\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${title}</title>\n<style>\n :root { color-scheme: light dark; }\n * { box-sizing: border-box; }\n body {\n margin: 0;\n font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;\n background: light-dark(#fafafa, #111);\n color: light-dark(#111, #eee);\n }\n header {\n display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap;\n padding: 0.9rem 1.25rem;\n border-bottom: 1px solid light-dark(#e2e2e2, #2a2a2a);\n position: sticky; top: 0;\n background: inherit;\n }\n header .brand { font-weight: 600; color: light-dark(#0891b2, #22d3ee); }\n header code { font-family: ui-monospace, monospace; font-size: 0.9rem; }\n header .sides { margin-left: auto; font-size: 0.8rem; opacity: 0.7; }\n main { max-width: 1400px; margin: 1rem auto; padding: 0 1rem 2rem; }\n .diff-shell {\n border: 1px solid light-dark(#e2e2e2, #2a2a2a);\n border-radius: 8px; overflow: hidden;\n background: light-dark(#fff, #161616);\n }\n</style>\n</head>\n<body>\n<header>\n <span class=\"brand\">⧈ cella diff</span>\n <code>${escapeHtml(meta.filePath)}</code>\n <span class=\"sides\">${escapeHtml(meta.srcLabel)} ← → ${escapeHtml(meta.dstLabel)} ${note}</span>\n</header>\n<main>\n <!-- Declarative shadow DOM: the library's CSS targets :host, which only\n matches inside a shadow root (its browser component renders into one). -->\n <div class=\"diff-shell\">\n <template shadowrootmode=\"open\">\n${prerenderedHTML}\n </template>\n </div>\n</main>\n</body>\n</html>`;\n}\n\n/** Open a file or URL with the platform's default handler (best-effort: a\n * missing or failing opener is not fatal — the page path is printed anyway). */\nfunction openWithDefaultApp(target: string): void {\n try {\n if (process.platform === 'win32') {\n execFileSync('rundll32', ['url.dll,FileProtocolHandler', target], { stdio: 'ignore' });\n } else {\n execFileSync(process.platform === 'darwin' ? 'open' : 'xdg-open', [target], { stdio: 'ignore' });\n }\n } catch {\n // e.g. headless environment without a browser/opener\n }\n}\n\n/**\n * Render a diff page, write it to a stable temp path, and open it in the browser.\n *\n * The output path is keyed by repo name and file path and overwritten on each\n * view, so repeat views don't litter tmp and a browser refresh shows the latest\n * render.\n *\n * @returns Absolute path of the written HTML file.\n */\nexport async function openDiffInBrowser(patch: string, meta: DiffPageMeta, repoPath: string): Promise<string> {\n const html = await renderDiffPage(patch, meta);\n\n const dir = join(tmpdir(), `cella-diff-${basename(repoPath)}`);\n mkdirSync(dir, { recursive: true });\n const outPath = join(dir, `${meta.filePath.replace(/[^\\w.-]+/g, '-')}.html`);\n\n writeFileSync(outPath, html);\n openWithDefaultApp(outPath);\n return outPath;\n}\n","/**\n * Cleanup utilities for sync CLI v2.\n *\n * Handles worktree cleanup and signal handlers for graceful abort.\n * Uses a temp directory outside the repo so worktree doesn't appear in VSCode.\n */\n\nimport { existsSync, rmSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { basename, join } from 'node:path';\nimport process from 'node:process';\nimport pc from './colors';\nimport { warningMark } from './display';\nimport { listWorktrees, mergeAbort, removeWorktree } from './git';\n\n/**\n * Managed worktree kinds and their system-temp directory prefixes.\n *\n * - `sync`: temporary merge preview worktree. Registered for signal cleanup and\n * removed when the process exits.\n * - `view`: legacy \"upstream view\" worktree that backed VS Code diff links in\n * older CLI versions (before browser diffs). No longer created; the prefix is\n * kept so leftovers from previous versions are removed on the next run.\n */\nconst WORKTREE_PREFIXES = {\n sync: 'cella-sync-',\n view: 'cella-view-',\n} as const;\n\ntype WorktreeKind = keyof typeof WORKTREE_PREFIXES;\n\n/** Build the system-temp worktree path for a kind, keyed by repo name for uniqueness. */\nfunction buildWorktreePath(kind: WorktreeKind, repoPath: string): string {\n return join(tmpdir(), `${WORKTREE_PREFIXES[kind]}${basename(repoPath)}`);\n}\n\n/** Get the temporary sync worktree path in system temp directory (invisible to VSCode). */\nexport function getWorktreePath(repoPath: string): string {\n return buildWorktreePath('sync', repoPath);\n}\n\n/** Track if cleanup is registered */\nlet cleanupRegistered = false;\n\n/** Track current worktree for cleanup */\nlet currentWorktreePath: string | null = null;\nlet currentRepoPath: string | null = null;\n\n/**\n * Register a worktree for cleanup on exit/abort.\n */\nexport function registerWorktree(repoPath: string, worktreePath: string): void {\n currentRepoPath = repoPath;\n currentWorktreePath = worktreePath;\n}\n\n/**\n * Unregister the worktree (call after successful cleanup).\n */\nfunction unregisterWorktree(): void {\n currentRepoPath = null;\n currentWorktreePath = null;\n}\n\n/**\n * Clean up the worktree directory.\n */\nexport async function cleanupWorktree(repoPath: string, worktreePath: string): Promise<void> {\n // Try git worktree remove first\n await removeWorktree(repoPath, worktreePath);\n\n // Force remove directory if it still exists\n if (existsSync(worktreePath)) {\n rmSync(worktreePath, { recursive: true, force: true });\n }\n\n unregisterWorktree();\n}\n\n/**\n * Clean up any leftover worktrees from a previous (interrupted) run, including\n * the legacy upstream-view worktree created by older CLI versions.\n * No-op when no leftovers exist (the common case).\n */\nexport async function cleanupLeftoverWorktrees(repoPath: string): Promise<void> {\n for (const kind of Object.keys(WORKTREE_PREFIXES) as WorktreeKind[]) {\n const worktreePath = buildWorktreePath(kind, repoPath);\n if (existsSync(worktreePath)) {\n await cleanupWorktree(repoPath, worktreePath);\n }\n }\n\n // Also prune any orphaned git worktree references for our managed prefixes.\n const prefixes = Object.values(WORKTREE_PREFIXES);\n const worktrees = await listWorktrees(repoPath);\n for (const wt of worktrees) {\n if (prefixes.some((prefix) => wt.includes(prefix)) && !existsSync(wt)) {\n await removeWorktree(repoPath, wt);\n }\n }\n}\n\n/**\n * Handle abort signal (Ctrl+C).\n */\nasync function handleAbort(signal: string): Promise<void> {\n console.info();\n console.info(`${warningMark} Interrupted (${signal}) - cleaning up...`);\n\n if (currentRepoPath && currentWorktreePath) {\n try {\n // Try to abort any in-progress merge in the worktree\n await mergeAbort(currentWorktreePath);\n } catch {\n // Ignore - merge may not be in progress\n }\n\n try {\n await cleanupWorktree(currentRepoPath, currentWorktreePath);\n console.info(`${pc.green('✓')} no changes were made to your repository.`);\n } catch (error) {\n console.error(\n `${pc.red('✗')} failed to clean up worktree: ${error instanceof Error ? error.message : 'unknown error'}`,\n );\n }\n }\n\n process.exit(1);\n}\n\n/**\n * Register signal handlers for graceful cleanup.\n */\nexport function registerSignalHandlers(): void {\n if (cleanupRegistered) return;\n\n process.on('SIGINT', () => handleAbort('SIGINT'));\n process.on('SIGTERM', () => handleAbort('SIGTERM'));\n\n cleanupRegistered = true;\n}\n","/**\n * Git command helpers for sync CLI v2.\n *\n * Provides typed wrappers around common git operations.\n */\n\nimport { execFile } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readdir, rmdir, unlink } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { getEnvSnapshot } from './env';\nimport { MANIFEST_FILE, readManifestBase, type SyncManifest } from './manifest';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Sanitize text by redacting credentials from URLs.\n * Prevents accidental credential exposure in error messages (CWE-532).\n */\nfunction sanitizeCredentials(text: string): string {\n return text.replace(/https?:\\/\\/[^@\\s]+@/g, (match) => {\n const protocol = match.startsWith('https') ? 'https' : 'http';\n return `${protocol}://***@`;\n });\n}\n\n/** Options for git command execution */\ninterface GitCommandOptions {\n /** Skip editor prompts (for merge commits, etc.) */\n skipEditor?: boolean;\n /** Maximum buffer size for stdout (default: 50MB) */\n maxBuffer?: number;\n /** Ignore command errors (return empty string instead of throwing) */\n ignoreErrors?: boolean;\n /** Additional environment variables for the git command */\n env?: Record<string, string>;\n}\n\n/**\n * Executes a git command and returns trimmed stdout.\n *\n * @param args - Git command arguments (e.g., ['status', '--porcelain'])\n * @param cwd - Working directory for the command\n * @param options - Command execution options\n * @returns Trimmed stdout from the command\n */\nexport async function git(args: string[], cwd: string, options: GitCommandOptions = {}): Promise<string> {\n const env = {\n ...getEnvSnapshot(),\n ...(options.skipEditor ? { GIT_EDITOR: 'true' } : {}),\n ...options.env,\n };\n\n const maxBuffer = options.maxBuffer ?? 50 * 1024 * 1024; // 50MB default\n\n try {\n const { stdout } = await execFileAsync('git', args, { cwd, env, maxBuffer });\n return stdout.trim();\n } catch (error) {\n if (options.ignoreErrors) return '';\n // Sanitize to prevent credential leakage from git remote URLs\n if (error instanceof Error) {\n error.message = sanitizeCredentials(error.message);\n }\n throw error;\n }\n}\n\n/**\n * Get the current branch name.\n */\nexport async function getCurrentBranch(cwd: string): Promise<string> {\n return git(['rev-parse', '--abbrev-ref', 'HEAD'], cwd);\n}\n\n/**\n * Switch to an existing branch.\n */\nexport async function switchBranch(cwd: string, branch: string): Promise<void> {\n await git(['switch', branch], cwd);\n}\n\n/**\n * Create and check out a new branch from a specific start point (branch/ref).\n */\nexport async function createBranchFrom(cwd: string, branch: string, startPoint: string): Promise<void> {\n await git(['switch', '-c', branch, startPoint], cwd);\n}\n\n/**\n * Delete a local branch (force). No-op if it doesn't exist.\n */\nexport async function deleteBranch(cwd: string, branch: string): Promise<void> {\n await git(['branch', '-D', branch], cwd, { ignoreErrors: true });\n}\n\n/**\n * Fast-forward the current branch from its upstream tracking branch.\n * Best-effort: ignores errors (e.g. no origin, offline, or nothing to pull).\n */\nexport async function pullFastForward(cwd: string): Promise<void> {\n await git(['pull', '--ff-only'], cwd, { ignoreErrors: true, skipEditor: true });\n}\n\n/** How the current branch compares to its upstream tracking branch. */\nexport interface UpstreamStatus {\n /** Upstream tracking ref (e.g. `origin/main`), or null when none is configured. */\n upstream: string | null;\n /** Commits the local branch has that its upstream doesn't. */\n ahead: number;\n /** Commits the upstream has that the local branch doesn't. */\n behind: number;\n}\n\n/**\n * Fetch the current branch's upstream, then report how far ahead/behind local is.\n *\n * The fetch is best-effort so an offline/no-remote run still returns whatever is already local.\n * Returns `upstream: null` when the branch has no tracking branch configured (local-only repo).\n */\nexport async function getUpstreamStatus(cwd: string): Promise<UpstreamStatus> {\n const upstream = await git(['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'], cwd, {\n ignoreErrors: true,\n });\n if (!upstream) return { upstream: null, ahead: 0, behind: 0 };\n\n // Refresh the remote-tracking ref so the comparison reflects the remote's latest state.\n const remote = upstream.split('/')[0];\n await git(['fetch', remote], cwd, { ignoreErrors: true, skipEditor: true });\n\n const counts = await git(['rev-list', '--left-right', '--count', `HEAD...${upstream}`], cwd, { ignoreErrors: true });\n const [ahead, behind] = counts.split(/\\s+/).map((n) => Number.parseInt(n, 10) || 0);\n return { upstream, ahead: ahead ?? 0, behind: behind ?? 0 };\n}\n\n/**\n * Push a branch to a remote, setting upstream tracking.\n *\n * `forceWithLease` allows a rewritten branch (see `flattenBranch`) to replace its previously\n * pushed version, while still refusing to overwrite remote commits we haven't seen.\n */\nexport async function pushBranch(\n cwd: string,\n remote: string,\n branch: string,\n options: { forceWithLease?: boolean } = {},\n): Promise<void> {\n await git(['push', '-u', ...(options.forceWithLease ? ['--force-with-lease'] : []), remote, branch], cwd);\n}\n\n/**\n * List merge commits made on the current branch itself: commits with two parents on the\n * first-parent chain from HEAD down to where the branch forked off `baseRef` (newest first).\n *\n * `--first-parent` keeps the walk on the branch's own commits, so merge commits that merely\n * exist inside a merged-in history (e.g. upstream's internal merges) don't count.\n */\nexport async function listBranchMergeCommits(cwd: string, baseRef: string): Promise<string[]> {\n const out = await git(['rev-list', '--merges', '--first-parent', `${baseRef}..HEAD`], cwd, { ignoreErrors: true });\n return out ? out.split('\\n').filter(Boolean) : [];\n}\n\n/**\n * Rewrite the current branch as one commit with `message`, parented on the point where the\n * branch forked off `baseRef`. The tree (content) is kept exactly as-is — only the commit\n * graph changes, so the branch's diff against the base is untouched.\n *\n * Companion to `commitSquash` for commits that already happened: a manual `git commit` during\n * a sync merge records a two-parent merge commit, which makes the PR list the upstream\n * branch's entire (unshared) history. Flattening restores the single-commit shape.\n */\nexport async function flattenBranch(cwd: string, baseRef: string, message: string): Promise<void> {\n const parent = await getMergeBase(cwd, baseRef, 'HEAD');\n const tree = await git(['rev-parse', 'HEAD^{tree}'], cwd);\n const commit = await git(['commit-tree', tree, '-p', parent, '-m', message], cwd);\n await git(['reset', '--hard', commit], cwd);\n}\n\n/**\n * Commit the staged changes as a single-parent commit, discarding any in-progress merge state.\n *\n * A normal commit with `MERGE_HEAD` present records a two-parent merge commit. Because the fork\n * doesn't share pushed ancestry with upstream (the local `git replace` graft that makes merges\n * incremental is never pushed), such a merge commit makes the PR list the upstream branch's\n * entire history. Removing the merge state first collapses the staged delta into one clean\n * commit, so the PR shows a single commit with the incremental diff.\n */\nexport async function commitSquash(cwd: string, message: string): Promise<void> {\n for (const file of ['MERGE_HEAD', 'MERGE_MSG', 'MERGE_MODE']) {\n const path = join(cwd, '.git', file);\n if (existsSync(path)) await unlink(path);\n }\n await git(['commit', '-m', message], cwd, { skipEditor: true });\n}\n\n/**\n * Stage every change in the working tree (`git add -A`), including untracked and deleted files.\n */\nexport async function stageAll(cwd: string): Promise<void> {\n await git(['add', '-A'], cwd);\n}\n\n/**\n * Whether a merge is currently in progress (MERGE_HEAD present).\n */\nexport function mergeInProgress(cwd: string): boolean {\n return existsSync(join(cwd, '.git', 'MERGE_HEAD'));\n}\n\n/**\n * Get the abbreviated (short) SHA for a ref.\n */\nexport async function getShortSha(cwd: string, ref: string): Promise<string> {\n return git(['rev-parse', '--short', ref], cwd);\n}\n\n/**\n * Count uncommitted working tree entries using porcelain status.\n */\nexport async function getWorkingTreeChangeCount(cwd: string): Promise<number> {\n const status = await git(['status', '--porcelain'], cwd);\n if (!status) return 0;\n return status.split('\\n').filter(Boolean).length;\n}\n\n/**\n * Check if a remote exists.\n */\nasync function remoteExists(cwd: string, remoteName: string): Promise<boolean> {\n const remotes = await git(['remote'], cwd);\n return remotes.split('\\n').includes(remoteName);\n}\n\n/**\n * Get the URL of a remote.\n */\nexport async function getRemoteUrl(cwd: string, remoteName: string): Promise<string | null> {\n try {\n const url = await git(['remote', 'get-url', remoteName], cwd, { ignoreErrors: true });\n return url.trim() || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Add a remote if it doesn't exist.\n */\nexport async function ensureRemote(cwd: string, remoteName: string, url: string): Promise<void> {\n if (await remoteExists(cwd, remoteName)) {\n // Update URL if remote exists\n await git(['remote', 'set-url', remoteName, url], cwd);\n } else {\n await git(['remote', 'add', remoteName, url], cwd);\n }\n}\n\n/**\n * Fetch from a remote.\n */\nexport async function fetch(cwd: string, remoteName: string): Promise<void> {\n await git(['fetch', remoteName], cwd);\n}\n\n/**\n * Fetch upstream tags into a remote-scoped namespace (`refs/<remoteName>/tags/*`)\n * instead of the local `refs/tags/*`. This keeps cella's release tags from\n * colliding with the fork's own release tags (forks run their own release-please).\n * `--no-tags` prevents git from also writing them into `refs/tags/*`.\n */\nexport async function fetchUpstreamTags(cwd: string, remoteName: string): Promise<void> {\n await git(['fetch', remoteName, '--no-tags', `+refs/tags/*:refs/${remoteName}/tags/*`], cwd);\n}\n\n/**\n * Resolve the latest upstream release tag (semver-sorted `v*` tag) from the\n * remote-scoped tag namespace. Excludes non-template tags (e.g. `create-cella-v*`).\n * Returns the short tag name and its full ref, or null when no release exists.\n */\nexport async function resolveLatestReleaseTag(\n cwd: string,\n remoteName: string,\n): Promise<{ tag: string; ref: string } | null> {\n const prefix = `refs/${remoteName}/tags/`;\n const output = await git(['for-each-ref', '--sort=-version:refname', '--format=%(refname)', prefix], cwd, {\n ignoreErrors: true,\n });\n if (!output) return null;\n for (const line of output.split('\\n')) {\n const ref = line.trim();\n if (!ref) continue;\n const tag = ref.slice(prefix.length);\n // Template release tags look like 'v0.5.0'; skip component tags like 'create-cella-v*'.\n if (/^v\\d/.test(tag)) return { tag, ref };\n }\n return null;\n}\n\n/**\n * Get the latest commit info from a ref.\n */\nexport async function getCommitInfo(\n cwd: string,\n ref: string,\n): Promise<{ hash: string; message: string; date: string }> {\n const format = '%H%n%s%n%ar'; // hash, subject, relative date\n const output = await git(['log', '-1', `--format=${format}`, ref], cwd);\n const [hash, message, date] = output.split('\\n');\n return { hash, message, date };\n}\n\n/**\n * Count the number of commits between two refs.\n * Returns the number of commits in `toRef` that are not in `fromRef`.\n */\nexport async function countCommitsBetween(cwd: string, fromRef: string, toRef: string): Promise<number> {\n const output = await git(['rev-list', '--count', `${fromRef}..${toRef}`], cwd);\n return Number.parseInt(output.trim(), 10) || 0;\n}\n\n/** Commit metadata for a single log entry */\nexport interface CommitRangeEntry {\n hash: string;\n message: string;\n date: string;\n}\n\n/**\n * List commits in a ref range.\n *\n * By default this returns commits oldest-first to match GitHub compare ordering.\n * Supports skip+limit pagination so callers can show only the most recent N commits\n * without fetching the entire range.\n */\nexport async function listCommitsBetween(\n cwd: string,\n fromRef: string,\n toRef: string,\n options: {\n oldestFirst?: boolean;\n skip?: number;\n limit?: number;\n } = {},\n): Promise<CommitRangeEntry[]> {\n const { oldestFirst = true, skip = 0, limit } = options;\n const args = ['log', '--format=%H%x1f%s%x1f%ar'];\n\n if (oldestFirst) args.push('--reverse');\n args.push(`${fromRef}..${toRef}`);\n\n const output = await git(args, cwd, { ignoreErrors: true });\n if (!output) return [];\n\n const commits: CommitRangeEntry[] = [];\n for (const line of output.split('\\n')) {\n if (!line) continue;\n const [hash, message, date] = line.split('\\x1f');\n if (!hash || !message || !date) continue;\n commits.push({ hash, message, date });\n }\n\n const normalizedSkip = Math.max(0, skip);\n const normalizedLimit = typeof limit === 'number' && limit > 0 ? limit : undefined;\n\n if (normalizedSkip === 0 && normalizedLimit === undefined) {\n return commits;\n }\n\n const start = Math.min(normalizedSkip, commits.length);\n const end = normalizedLimit === undefined ? commits.length : Math.min(start + normalizedLimit, commits.length);\n return commits.slice(start, end);\n}\n\n/**\n * File change info with date and commit hash.\n */\ninterface FileChangeInfo {\n date: string;\n hash: string;\n /** Unix epoch seconds of the change, for sorting */\n timestamp: number;\n}\n\n/**\n * Get the relative date and commit hash of the last change for all files in a range.\n * Returns a map of filePath -> { date, hash }.\n * Uses a single git command to get all info efficiently.\n */\nexport async function getFileChangeInfo(\n cwd: string,\n fromRef: string,\n toRef: string,\n): Promise<Map<string, FileChangeInfo>> {\n const info = new Map<string, FileChangeInfo>();\n\n try {\n // Get all commits in range with their files, dates, and hashes\n // Format: hash, epoch timestamp, relative date, then list of files changed\n const output = await git(['log', '--name-only', '--format=%h %ct %ar', `${fromRef}..${toRef}`], cwd, {\n ignoreErrors: true,\n });\n\n if (!output.trim()) return info;\n\n const lines = output.split('\\n');\n let currentHash = '';\n let currentDate = '';\n let currentTimestamp = 0;\n\n for (const line of lines) {\n if (!line) continue;\n\n // Check if this is a hash+timestamp+date line (starts with short hash)\n const match = line.match(/^([a-f0-9]{7,})\\s+(\\d+)\\s+(.+)$/);\n if (match) {\n currentHash = match[1];\n currentTimestamp = Number(match[2]);\n currentDate = match[3];\n } else if (currentHash && currentDate && !info.has(line)) {\n // This is a file path - only set if not already set (we want most recent)\n info.set(line, { date: currentDate, hash: currentHash, timestamp: currentTimestamp });\n }\n }\n } catch {\n // Ignore errors, return empty map\n }\n\n return info;\n}\n\n/**\n * Check if the working tree is clean (no uncommitted changes).\n */\nexport async function isClean(cwd: string): Promise<boolean> {\n const status = await git(['status', '--porcelain'], cwd);\n return !status;\n}\n\n/**\n * Throw if the working tree has uncommitted changes.\n * `subject` labels the repo in the error (e.g. 'working directory', 'fork').\n */\nexport async function assertClean(cwd: string, subject = 'working directory'): Promise<void> {\n if (!(await isClean(cwd))) {\n throw new Error(`${subject} has uncommitted changes. please commit or stash before syncing.`);\n }\n}\n\n/**\n * Create a worktree from a commit (detached HEAD).\n * Uses --detach to avoid \"branch already checked out\" errors.\n */\nexport async function createWorktree(cwd: string, worktreePath: string, commitRef: string): Promise<void> {\n await git(['worktree', 'add', '--detach', worktreePath, commitRef], cwd);\n}\n\n/**\n * Remove a worktree.\n */\nexport async function removeWorktree(cwd: string, worktreePath: string): Promise<void> {\n await git(['worktree', 'remove', worktreePath, '--force'], cwd, { ignoreErrors: true });\n await git(['worktree', 'prune'], cwd, { ignoreErrors: true });\n}\n\n/**\n * List existing worktrees.\n */\nexport async function listWorktrees(cwd: string): Promise<string[]> {\n const output = await git(['worktree', 'list', '--porcelain'], cwd);\n const lines = output.split('\\n');\n const paths: string[] = [];\n for (const line of lines) {\n if (line.startsWith('worktree ')) {\n paths.push(line.slice(9));\n }\n }\n return paths;\n}\n\n/**\n * Perform a merge in the current directory.\n * Always uses --no-ff to prevent fast-forward, ensuring HEAD stays in place\n * and MERGE_HEAD is created for proper merge state tracking.\n */\nexport async function merge(\n cwd: string,\n ref: string,\n options: { noCommit?: boolean; noEdit?: boolean } = {},\n): Promise<{ success: boolean; conflicts: string[] }> {\n const args = ['merge', '--no-ff', ref];\n if (options.noCommit) args.push('--no-commit');\n if (options.noEdit) args.push('--no-edit');\n\n try {\n await git(args, cwd, { skipEditor: true });\n return { success: true, conflicts: [] };\n } catch (error) {\n // Check for conflicts\n const conflicts = await getConflictedFiles(cwd);\n if (conflicts.length > 0) {\n return { success: false, conflicts };\n }\n throw error;\n }\n}\n\n/**\n * Get list of files with merge conflicts.\n */\nexport async function getConflictedFiles(cwd: string): Promise<string[]> {\n const output = await git(['diff', '--name-only', '--diff-filter=U'], cwd, { ignoreErrors: true });\n if (!output) return [];\n return output.split('\\n').filter(Boolean);\n}\n\n/**\n * Abort an in-progress merge.\n */\nexport async function mergeAbort(cwd: string): Promise<void> {\n await git(['merge', '--abort'], cwd, { ignoreErrors: true });\n}\n\n/**\n * Check if a file exists at a ref.\n */\nexport async function fileExistsAtRef(cwd: string, ref: string, filePath: string): Promise<boolean> {\n const result = await git(['ls-tree', '--name-only', ref, '--', filePath], cwd, { ignoreErrors: true });\n return result !== '';\n}\n\n/**\n * Checkout a file from a specific ref.\n * Used to restore files from upstream that don't exist in fork.\n */\nexport async function checkoutFromRef(cwd: string, ref: string, filePath: string): Promise<void> {\n await git(['checkout', ref, '--', filePath], cwd);\n}\n\n/**\n * Restore a path from a ref into the working tree only, leaving the index untouched.\n * Useful when we want adopted changes to remain unstaged for review.\n */\nexport async function restoreWorktreeFromRef(cwd: string, ref: string, filePath: string): Promise<void> {\n await git(['restore', `--source=${ref}`, '--worktree', '--', filePath], cwd);\n}\n\n/**\n * Get the merge base between two refs.\n */\nexport async function getMergeBase(cwd: string, ref1: string, ref2: string): Promise<string> {\n return git(['merge-base', ref1, ref2], cwd);\n}\n\n/** File change status codes from git diff-tree */\ntype FileChangeStatus = 'A' | 'D' | 'M' | 'T' | 'R';\n\n/** File change info from git diff-tree */\ninterface FileChange {\n status: FileChangeStatus;\n baseHash: string | null;\n targetHash: string | null;\n /** For renames: the original path (before rename) */\n oldPath?: string;\n /** For renames: the new path (after rename) */\n newPath?: string;\n}\n\n/**\n * Get files changed between two refs using diff-tree.\n * Returns a map of filePath -> FileChange\n *\n * This is much faster than checking each file individually.\n * Status codes: A=added, D=deleted, M=modified, T=type-changed, R=renamed\n *\n * Uses -M90% to detect renames with 90% similarity threshold.\n * For renames, the map key is the NEW path, with oldPath stored in the value.\n */\nexport async function getFileChanges(\n cwd: string,\n baseRef: string,\n targetRef: string,\n): Promise<Map<string, FileChange>> {\n // Use diff-tree with -M90% to detect renames (90% similarity threshold)\n // Format for non-renames: :oldmode newmode oldhash newhash status\\tpath\n // Format for renames: :oldmode newmode oldhash newhash Rxx\\toldpath\\tnewpath\n const output = await git(['diff-tree', '-r', '-M90%', '--no-commit-id', baseRef, targetRef], cwd, {\n ignoreErrors: true,\n });\n\n const changes = new Map<string, FileChange>();\n\n if (!output) return changes;\n\n for (const line of output.split('\\n')) {\n if (!line) continue;\n\n // Check for rename first (Rxx status with two paths)\n // Format: :100644 100644 abc123... def456... R100 oldpath\\tnewpath\n // Note: space after Rxx, then tab between old and new paths\n const renameMatch = line.match(/^:\\d+ \\d+ ([a-f0-9]+) ([a-f0-9]+) R\\d*\\s+(.+)\\t(.+)$/);\n if (renameMatch) {\n const [, baseHash, targetHash, oldPath, newPath] = renameMatch;\n changes.set(newPath, {\n status: 'R',\n baseHash: baseHash === '0'.repeat(40) ? null : baseHash,\n targetHash: targetHash === '0'.repeat(40) ? null : targetHash,\n oldPath,\n newPath,\n });\n continue;\n }\n\n // Parse non-rename: :100644 100644 abc123... def456... M\\tpath/to/file\n const match = line.match(/^:\\d+ \\d+ ([a-f0-9]+) ([a-f0-9]+) ([ADMT])\\t(.+)$/);\n if (match) {\n const [, baseHash, targetHash, status, filePath] = match;\n changes.set(filePath, {\n status: status as 'A' | 'D' | 'M' | 'T',\n baseHash: baseHash === '0'.repeat(40) ? null : baseHash,\n targetHash: targetHash === '0'.repeat(40) ? null : targetHash,\n });\n }\n }\n\n return changes;\n}\n\n/**\n * Get all file hashes at a ref using ls-tree (batch operation).\n * Returns a Map of filePath -> hash for quick lookups.\n */\nexport async function getFileHashesAtRef(cwd: string, ref: string): Promise<Map<string, string>> {\n const output = await git(['ls-tree', '-r', ref], cwd);\n const hashes = new Map<string, string>();\n\n if (!output) return hashes;\n\n for (const line of output.split('\\n')) {\n if (!line) continue;\n // Parse: <mode> <type> <hash>\\t<path>\n const match = line.match(/^\\d+ \\w+ ([a-f0-9]+)\\t(.+)$/);\n if (match) {\n const [, hash, filePath] = match;\n hashes.set(filePath, hash);\n }\n }\n\n return hashes;\n}\n\n/**\n * Restore a file to HEAD version (our version during merge).\n * Updates both index and worktree to match HEAD.\n *\n * Uses `git checkout HEAD --` instead of `git restore --source=HEAD` because\n * `git restore` fails on unmerged (conflicted) paths during a merge, while\n * `git checkout HEAD --` resolves them by taking HEAD's version.\n */\nexport async function restoreToHead(cwd: string, filePath: string): Promise<void> {\n await git(['checkout', 'HEAD', '--', filePath], cwd);\n}\n\n/**\n * Batch restore multiple files to HEAD version in a single git command.\n * Much faster than calling restoreToHead for each file individually.\n * Reduces IDE file watcher events by completing all restores at once.\n *\n * Uses `git checkout HEAD --` instead of `git restore --source=HEAD` because\n * `git restore` fails on unmerged (conflicted) paths during a merge, while\n * `git checkout HEAD --` resolves them by taking HEAD's version.\n */\nexport async function batchRestoreToHead(cwd: string, filePaths: string[]): Promise<void> {\n if (filePaths.length === 0) return;\n await git(['checkout', 'HEAD', '--', ...filePaths], cwd);\n}\n\n/**\n * Remove a file from index with tracked delete (git rm).\n * Records a deletion in the merge result.\n */\nexport async function gitRm(cwd: string, filePath: string): Promise<void> {\n await git(['rm', '-f', '--', filePath], cwd, { ignoreErrors: true });\n}\n\n/**\n * Batch remove multiple files from index with tracked delete.\n * Much faster than calling gitRm for each file individually.\n */\nexport async function batchGitRm(cwd: string, filePaths: string[]): Promise<void> {\n if (filePaths.length === 0) return;\n await git(['rm', '-f', '--', ...filePaths], cwd, { ignoreErrors: true });\n}\n\n/**\n * Get files staged as new additions in the index (diff-filter=A vs HEAD).\n * These are files that don't exist at HEAD but were brought in by a merge.\n */\nexport async function getStagedNewFiles(cwd: string): Promise<string[]> {\n const output = await git(['diff', '--cached', '--name-only', '--diff-filter=A'], cwd, { ignoreErrors: true });\n return output ? output.split('\\n').filter(Boolean) : [];\n}\n\n/**\n * Remove files from the index only (--cached), leaving the working tree untouched.\n * Useful for cleaning up files staged by a merge that shouldn't be committed.\n */\nexport async function batchUnstageFiles(cwd: string, filePaths: string[]): Promise<void> {\n if (filePaths.length === 0) return;\n await git(['rm', '--cached', '-f', '--', ...filePaths], cwd, { ignoreErrors: true });\n}\n\n/**\n * Move/rename a file using git mv.\n * Creates parent directories if needed and preserves git history.\n */\nexport async function gitMv(cwd: string, oldPath: string, newPath: string): Promise<void> {\n // Ensure parent directory exists for new path\n const newDir = dirname(join(cwd, newPath));\n await mkdir(newDir, { recursive: true });\n\n await git(['mv', '-f', oldPath, newPath], cwd);\n}\n\n/**\n * Check if a file exists in the worktree filesystem.\n */\nexport async function fileExistsInWorktree(cwd: string, filePath: string): Promise<boolean> {\n return existsSync(join(cwd, filePath));\n}\n\n/**\n * Remove a file from the worktree filesystem if it exists.\n * Used to clean up files that git rm may not have removed (e.g., after squash merge).\n */\nexport async function removeFileFromWorktree(cwd: string, filePath: string): Promise<void> {\n const fullPath = join(cwd, filePath);\n try {\n await unlink(fullPath);\n // Try to clean up empty parent directories\n await cleanupEmptyParentDirs(cwd, dirname(filePath));\n } catch {\n // File doesn't exist or can't be removed - ignore\n }\n}\n\n/**\n * Fully remove a file: tracked delete from the index (git rm) plus filesystem removal\n * for cases git rm leaves behind (e.g. during a merge), including empty parent dirs.\n */\nexport async function removeFileFully(cwd: string, filePath: string): Promise<void> {\n await gitRm(cwd, filePath);\n await removeFileFromWorktree(cwd, filePath);\n}\n\n/**\n * Recursively remove empty parent directories up to (but not including) the root.\n * Stops when encountering a non-empty directory or the root.\n */\nasync function cleanupEmptyParentDirs(cwd: string, relativePath: string): Promise<void> {\n if (!relativePath || relativePath === '.') return;\n\n const fullPath = join(cwd, relativePath);\n try {\n const entries = await readdir(fullPath);\n if (entries.length === 0) {\n await rmdir(fullPath);\n // Recurse to parent\n await cleanupEmptyParentDirs(cwd, dirname(relativePath));\n }\n } catch {\n // Directory doesn't exist, not empty, or can't be removed - stop\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Sync ref tracking & merge-base recovery\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Store the upstream commit hash after a successful sync.\n * Used to recover correct merge-base when squash strategy creates single-parent commits.\n *\n * Also records the fork HEAD at store time as `refs/cella/last-sync-head`. The last-sync\n * ref is written while the merge is still staged (before the user commits), so it cannot be\n * trusted on its own: if the user runs `git merge --abort`, HEAD never advances and the ref\n * is left pointing at an upstream commit that was never actually integrated. Recording HEAD\n * lets `getEffectiveMergeBase` detect that an aborted/uncommitted merge produced a stale ref.\n */\nexport async function storeLastSyncRef(cwd: string, upstreamHash: string): Promise<void> {\n await git(['update-ref', 'refs/cella/last-sync', upstreamHash], cwd);\n const head = await git(['rev-parse', 'HEAD'], cwd, { ignoreErrors: true });\n if (head) {\n await git(['update-ref', 'refs/cella/last-sync-head', head], cwd);\n }\n}\n\n/** Stage a single path (git add). Best-effort — never throws. */\nexport async function stagePath(cwd: string, path: string): Promise<void> {\n await git(['add', '--', path], cwd, { ignoreErrors: true });\n}\n\n/**\n * Get the stored last-sync upstream ref.\n * Returns null if no previous sync has been recorded.\n */\nexport async function getStoredSyncRef(cwd: string): Promise<string | null> {\n const ref = await git(['rev-parse', 'refs/cella/last-sync'], cwd, { ignoreErrors: true });\n return ref || null;\n}\n\n/**\n * Get the fork HEAD that was recorded when the last-sync ref was stored.\n * Returns null if no HEAD was recorded.\n */\nexport async function getStoredSyncHead(cwd: string): Promise<string | null> {\n const ref = await git(['rev-parse', 'refs/cella/last-sync-head'], cwd, { ignoreErrors: true });\n return ref || null;\n}\n\n/**\n * Read the sync manifest committed at a specific ref.\n *\n * This intentionally reads from git, not the working tree: a staged/aborted sync can leave the\n * worktree manifest ahead of the committed trunk, and that must not validate a sync point.\n */\nexport async function readManifestAtRef(cwd: string, ref: string): Promise<SyncManifest | null> {\n const raw = await git(['show', `${ref}:${MANIFEST_FILE}`], cwd, { ignoreErrors: true });\n if (!raw) return null;\n\n try {\n const parsed = JSON.parse(raw) as SyncManifest;\n const commit = parsed?.upstream?.commit;\n if (typeof commit !== 'string' || !/^[0-9a-f]{40}$/i.test(commit)) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\n/** The upstream base commit SHA from the manifest committed at `ref`, or null. */\nexport async function readManifestBaseAtRef(cwd: string, ref: string): Promise<string | null> {\n const manifest = await readManifestAtRef(cwd, ref);\n return manifest ? manifest.upstream.commit.toLowerCase() : null;\n}\n\n/**\n * Read the `version` field of the root `package.json` committed at a ref.\n * Returns null when the file is absent or unparsable.\n */\nexport async function readPackageVersionAtRef(cwd: string, ref: string): Promise<string | null> {\n const raw = await git(['show', `${ref}:package.json`], cwd, { ignoreErrors: true });\n if (!raw) return null;\n\n try {\n const version = (JSON.parse(raw) as { version?: unknown }).version;\n return typeof version === 'string' && version ? version : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Check whether a commit object is present in the local object store.\n */\nasync function commitObjectExists(cwd: string, sha: string): Promise<boolean> {\n try {\n await git(['cat-file', '-e', `${sha}^{commit}`], cwd);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get the root (parentless) commit of a ref's history. A create-cella scaffold has a\n * single rootless \"Initial commit\" whose tree is a frozen snapshot of the upstream\n * template at scaffold time. Returns null when no root is found.\n */\nasync function getRootCommit(cwd: string, ref: string): Promise<string | null> {\n const out = await git(['rev-list', '--max-parents=0', ref], cwd, { ignoreErrors: true });\n const roots = out.split('\\n').filter(Boolean);\n return roots.length > 0 ? roots[roots.length - 1] : null;\n}\n\n/** Max upstream commits scored when inferring a scaffold base by tree similarity. */\nconst SCAFFOLD_CANDIDATE_LIMIT = 400;\n\n/** Concurrent diff-tree scoring calls during scaffold-base inference. */\nconst SCAFFOLD_SCORE_CONCURRENCY = 10;\n\n/**\n * Reject an inferred scaffold base when more than this fraction of the root snapshot's\n * paths differ from the best-matching upstream commit. The template cleaner rewrites a\n * fixed handful of files and deselected optional modules remove a few folders, so a real\n * scaffold stays far below this; a hand-rolled repo blows past it.\n */\nconst SCAFFOLD_MATCH_MAX_DIFF_RATIO = 0.3;\n\n/**\n * Infer the upstream commit a scaffold was created from, by tree similarity.\n *\n * A create-cella scaffold's root commit is a frozen snapshot of the upstream tree at\n * scaffold time: the template cleaner only rewrites a handful of files (project name,\n * ports, changelog) and drops deselected module folders, so the vast majority of paths\n * stay byte-identical to exactly one upstream commit. Diff the root tree against recent\n * upstream commits and take the closest match — no provenance file needed.\n *\n * Candidates are bounded to upstream commits no newer than the root commit (plus a\n * clock-skew margin): the scaffold cannot come from a commit that didn't exist yet.\n * Neighboring candidates can tie when the commits between them only touch files the\n * scaffold rewrote anyway (upstream release commits do exactly this) — either tie is a\n * correct base for the 3-way merge, and newest wins.\n *\n * Returns null when no candidate matches convincingly (see SCAFFOLD_MATCH_MAX_DIFF_RATIO).\n */\nasync function inferScaffoldBase(cwd: string, headRef: string, upstreamRef: string): Promise<string | null> {\n const root = await getRootCommit(cwd, headRef);\n if (!root) return null;\n\n const rootDate = await git(['show', '-s', '--format=%cI', root], cwd, { ignoreErrors: true });\n if (!rootDate) return null;\n // A day of margin absorbs clock skew between the scaffolding machine and upstream committers.\n const before = new Date(new Date(rootDate).getTime() + 24 * 60 * 60 * 1000).toISOString();\n\n const revList = await git(\n ['rev-list', `--max-count=${SCAFFOLD_CANDIDATE_LIMIT}`, `--before=${before}`, upstreamRef],\n cwd,\n { ignoreErrors: true },\n );\n const candidates = revList.split('\\n').filter(Boolean);\n if (candidates.length === 0) return null;\n\n const totalPaths = (await git(['ls-tree', '-r', '--name-only', root], cwd)).split('\\n').filter(Boolean).length;\n if (totalPaths === 0) return null;\n\n // Score = differing paths between candidate and root snapshot. rev-list is newest-first\n // and strict `<` keeps the first (newest) candidate on ties.\n let best: { sha: string; diff: number } | null = null;\n outer: for (let i = 0; i < candidates.length; i += SCAFFOLD_SCORE_CONCURRENCY) {\n const chunk = candidates.slice(i, i + SCAFFOLD_SCORE_CONCURRENCY);\n const scores = await Promise.all(\n chunk.map(async (sha) => {\n try {\n const out = await git(['diff-tree', '-r', '--name-only', sha, root], cwd);\n return { sha, diff: out ? out.split('\\n').length : 0 };\n } catch {\n return { sha, diff: Number.POSITIVE_INFINITY };\n }\n }),\n );\n for (const score of scores) {\n if (!best || score.diff < best.diff) best = score;\n if (best.diff === 0) break outer; // byte-identical snapshot — cannot do better\n }\n }\n\n if (!best || best.diff / totalPaths > SCAFFOLD_MATCH_MAX_DIFF_RATIO) return null;\n return best.sha;\n}\n\n/**\n * Read the scaffold provenance trailer from the fork's root commit message.\n *\n * create-cella stamps `Cella-Base: <sha>` on the initial commit, recording the exact\n * upstream commit the scaffold snapshot was taken from. Riding in commit history, it\n * travels with push/clone — unlike a local ref — and needs no file in the worktree.\n */\nasync function readRootTrailerBase(cwd: string, headRef: string): Promise<string | null> {\n const root = await getRootCommit(cwd, headRef);\n if (!root) return null;\n const message = await git(['show', '-s', '--format=%B', root], cwd, { ignoreErrors: true });\n const match = message.match(/^cella-base:\\s*([0-9a-f]{40})$/im);\n return match ? match[1].toLowerCase() : null;\n}\n\n/**\n * Ensure a native git merge-base exists between the fork and upstream.\n *\n * A create-cella scaffold — or a fork whose upstream squashed its history — has unrelated\n * histories, so `git merge-base` finds nothing and every sync fails at the very first step.\n * This bootstraps ancestry non-destructively:\n * 1. If a native merge-base already exists, do nothing (the common case).\n * 2. Otherwise resolve the logical base commit: sources are tried in order and the first\n * one whose commit actually exists after the upstream fetch wins — the sync-point\n * record (`refs/cella/last-sync` ref, then committed/worktree `cella.manifest.json`),\n * then the scaffold origin (the root commit's `Cella-Base:` trailer, then tree-similarity\n * inference as reseed fallback for scaffolds whose trailer is absent or stale).\n * 3. Graft the fork's root commit onto that base with `git replace --graft`, so every native\n * git operation (merge-base and the 3-way merge itself) sees correct ancestry. The replace\n * ref is local-only and never pushed, so the fork's own published history stays clean.\n *\n * Throws an actionable error when no valid base can be determined.\n */\nexport async function ensureSyncBase(cwd: string, headRef: string, upstreamRef: string): Promise<void> {\n // Native ancestry already present — nothing to bootstrap.\n const nativeBase = await git(['merge-base', headRef, upstreamRef], cwd, { ignoreErrors: true });\n if (nativeBase) return;\n\n const sources: Array<() => Promise<string | null>> = [\n () => getStoredSyncRef(cwd),\n () => readManifestBaseAtRef(cwd, headRef),\n () => readManifestBase(cwd),\n () => readRootTrailerBase(cwd, headRef),\n () => inferScaffoldBase(cwd, headRef, upstreamRef),\n ];\n\n let baseSha: string | null = null;\n for (const source of sources) {\n const sha = await source();\n if (sha && (await commitObjectExists(cwd, sha))) {\n baseSha = sha;\n break;\n }\n }\n if (!baseSha) {\n throw new Error(\n `no common ancestor between the fork and '${upstreamRef}', and no sync base could be determined.\\n\\n` +\n 'This fork has unrelated history with upstream — typical for a create-cella scaffold, or after\\n' +\n 'upstream squashed its history — and no recorded or inferable base commit exists after fetching\\n' +\n 'upstream. Seed it manually with the upstream commit the fork was created from, then re-run sync:\\n\\n' +\n ' git update-ref refs/cella/last-sync <upstream-sha>\\n',\n );\n }\n\n const root = await getRootCommit(cwd, headRef);\n if (!root) throw new Error(\"could not determine the fork's root commit to bootstrap sync ancestry\");\n\n // Graft the fork root onto the base (idempotent via -f) so native git sees the ancestry.\n await git(['replace', '-f', '--graft', root, baseSha], cwd);\n\n // Record the base as the last-sync ref so future runs and the squash strategy stay consistent.\n await git(['update-ref', 'refs/cella/last-sync', baseSha], cwd);\n}\n\n/**\n * Check if one commit is an ancestor of another.\n */\nexport async function isAncestor(cwd: string, ancestor: string, descendant: string): Promise<boolean> {\n try {\n await git(['merge-base', '--is-ancestor', ancestor, descendant], cwd);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Legacy sync point for forks that last synced before the manifest was committed: the local\n * last-sync ref, guarded against aborted merges. The ref is written while the merge is still\n * staged; if the user ran `git merge --abort` instead of committing, HEAD never advanced past\n * the recorded sync HEAD and the upstream commits were never integrated, so the ref is discarded.\n */\nasync function getLegacySyncRef(cwd: string, headRef: string): Promise<string | null> {\n const storedRef = await getStoredSyncRef(cwd);\n if (!storedRef) return null;\n\n const storedHead = await getStoredSyncHead(cwd);\n if (storedHead) {\n const currentHead = await git(['rev-parse', headRef], cwd, { ignoreErrors: true });\n if (currentHead && currentHead === storedHead) return null;\n }\n\n return storedRef;\n}\n\n/**\n * Get the effective merge-base, preferring the recorded sync point when it's more recent.\n * This handles stale merge-base caused by previous squash syncs (single-parent commits\n * don't update git's merge-base graph).\n *\n * The manifest committed at `headRef` is the authoritative record: the sync engine stages it\n * inside every applied sync, so it lands iff the sync commit lands. That makes it immune to\n * aborted merges (never committed) and available on fresh clones and other machines (it\n * travels with the repo, unlike local refs). The local last-sync ref is only consulted as a\n * fallback for forks whose last sync predates the manifest.\n *\n * @returns The effective base commit, whether git's base was stale, and the recorded sync point\n */\nexport async function getEffectiveMergeBase(\n cwd: string,\n headRef: string,\n upstreamRef: string,\n): Promise<{ base: string; isStale: boolean; storedRef: string | null }> {\n const gitBase = await getMergeBase(cwd, headRef, upstreamRef);\n\n const recorded = (await readManifestBaseAtRef(cwd, headRef)) ?? (await getLegacySyncRef(cwd, headRef));\n if (!recorded) {\n return { base: gitBase, isStale: false, storedRef: null };\n }\n\n // Only prefer the recorded sync point when it is actually newer than git's own answer.\n const recordedIsNewer = await isAncestor(cwd, gitBase, recorded);\n if (recordedIsNewer && recorded !== gitBase) {\n return { base: recorded, isStale: true, storedRef: recorded };\n }\n\n return { base: gitBase, isStale: false, storedRef: recorded };\n}\n\n/**\n * Run `fn` with a temporary local graft that makes `baseSha` an ancestor of `headRef`, so\n * native git operations — merge-base resolution and the 3-way merge itself — see the recorded\n * sync point instead of a stale historical ancestor.\n *\n * Squash syncs advance the recorded sync point (manifest + `refs/cella/last-sync`) without\n * advancing git's commit graph, so a plain `git merge` replays every upstream change since the\n * last true merge ancestor: hunks the fork already integrated (or deliberately resolved away)\n * re-apply as clean auto-merges or re-conflict on every sync. The graft adds `baseSha` as an\n * extra parent of the `headRef` commit via `git replace --graft`; replace refs are local-only\n * and the ref is deleted right after `fn`, so nothing ever leaks into pushed history.\n *\n * Runs `fn` without grafting when the graft is unnecessary or unsafe:\n * - `baseSha` is already an ancestor of `headRef` (git's own merge-base is not stale), or\n * - a replacement object already exists for the `headRef` commit (never clobber, e.g. the\n * scaffold root graft from {@link ensureSyncBase} when the root commit is HEAD).\n */\nexport async function withTemporarySyncBaseGraft<T>(\n cwd: string,\n headRef: string,\n baseSha: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const headSha = await git(['rev-parse', headRef], cwd, { ignoreErrors: true });\n if (!headSha || !(await commitObjectExists(cwd, baseSha))) return fn();\n\n // Native ancestry already covers the base — nothing to graft.\n if (await isAncestor(cwd, baseSha, headSha)) return fn();\n\n // Never clobber an existing replacement object for this commit.\n const existingReplacement = await git(['replace', '-l', headSha], cwd, { ignoreErrors: true });\n if (existingReplacement) return fn();\n\n const parentsRaw = await git(['log', '-1', '--format=%P', headSha], cwd, { ignoreErrors: true });\n const parents = parentsRaw ? parentsRaw.split(/\\s+/) : [];\n\n await git(['replace', '-f', '--graft', headSha, ...parents, baseSha], cwd);\n try {\n return await fn();\n } finally {\n await git(['replace', '-d', headSha], cwd, { ignoreErrors: true });\n }\n}\n","/**\n * Cella sync manifest.\n *\n * A committed record of the last upstream sync point, living at the fork repo root as\n * `cella.manifest.json`. It serves two purposes:\n * 1. Machine: `upstream.commit` is the bootstrap seed `ensureSyncBase` uses to reconstruct\n * the merge-base on a clone that has no local `refs/cella/last-sync` (fresh clone, CI, a\n * second maintainer). Committed, so it travels with the repo — unlike the local ref.\n * 2. Human: records the upstream repo, tracking mode, release/commit and a GitHub link, so\n * each sync PR shows exactly which upstream point you moved to.\n *\n * Written and staged by the sync engine on every applied sync, so it stays in lockstep with\n * `refs/cella/last-sync` and rides along in the sync commit.\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\n/** Committed manifest filename at the fork repo root. */\nexport const MANIFEST_FILE = 'cella.manifest.json';\n\n/** The last upstream sync point recorded in {@link MANIFEST_FILE}. */\nexport interface SyncManifest {\n upstream: {\n /** GitHub slug of the upstream repo, e.g. 'cellajs/cella'. */\n repo?: string;\n /** Tracking mode at sync time. */\n track?: 'release' | 'branch';\n /** Integrated upstream commit SHA — the merge-base bootstrap seed. */\n commit: string;\n /** Release tag when tracking releases, else null. */\n release?: string | null;\n /** Human-readable link to the commit or release on GitHub. */\n url?: string;\n /** UTC timestamp of the sync (ISO 8601). */\n syncedAt?: string;\n };\n}\n\n/** Read and validate the manifest. Returns null when absent or malformed. */\nexport async function readSyncManifest(cwd: string): Promise<SyncManifest | null> {\n try {\n const parsed = JSON.parse(await readFile(join(cwd, MANIFEST_FILE), 'utf8')) as SyncManifest;\n const commit = parsed?.upstream?.commit;\n if (typeof commit !== 'string' || !/^[0-9a-f]{40}$/i.test(commit)) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\n/**\n * Return the recorded upstream base commit SHA, or null.\n * Bootstrap seed for {@link ensureSyncBase} when no local `refs/cella/last-sync` exists.\n */\nexport async function readManifestBase(cwd: string): Promise<string | null> {\n const manifest = await readSyncManifest(cwd);\n return manifest ? manifest.upstream.commit.toLowerCase() : null;\n}\n\n/** Write the manifest as pretty JSON with a trailing newline. */\nexport async function writeSyncManifest(cwd: string, manifest: SyncManifest): Promise<void> {\n await writeFile(join(cwd, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\\n`, 'utf8');\n}\n","/**\n * Direction-agnostic ref analyzer for sync CLI.\n *\n * Compares a \"local\" ref against an \"incoming\" ref using a shared merge-base,\n * classifying every changed file (identical / ahead / local / drifted / behind /\n * diverged / pinned / ignored / deleted / renamed). It works purely on git\n * plumbing (ls-tree, diff-tree, log) against refs — never the working tree.\n *\n * Both directions reuse it:\n * - sync (merge-engine): local = fork HEAD, incoming = upstream\n * - contributions: local = cella branch, incoming = fork branch\n *\n * The result fields `existsInFork`/`existsInUpstream` map to local/incoming\n * respectively (named for the sync direction, reused as-is for contributions).\n */\n\nimport type { AnalyzedFile, FileStatus } from '../config/types';\nimport { getFileChangeInfo, getFileChanges, getFileHashesAtRef } from '../utils/git';\n\n/** Predicates and options that steer classification (direction-specific). */\nexport interface AnalyzePredicates {\n /** True if the file is inside owned/ignored territory (never synced). */\n isIgnored: (path: string) => boolean;\n /** True if the file is pinned (local wins on conflict). */\n isPinned: (path: string) => boolean;\n /** Treat drifted files as behind (overwrite local with incoming). */\n hard?: boolean;\n}\n\n/** Progress callback type - receives a message string. */\ntype ProgressCallback = (message: string) => void;\n\n/**\n * Analyze files between a local and an incoming ref using a merge-base.\n *\n * @param repoPath - Repo where all refs are reachable (git ops run here)\n * @param localRef - The \"ours\" ref (e.g. fork HEAD, or cella branch)\n * @param incomingRef - The \"theirs\" ref (e.g. upstream, or fork branch)\n * @param mergeBaseRef - Common ancestor ref used for 3-way comparison\n * @param predicates - Direction-specific ignore/pin/hard behavior\n */\nexport async function analyzeRefs(\n repoPath: string,\n localRef: string,\n incomingRef: string,\n mergeBaseRef: string,\n predicates: AnalyzePredicates,\n onProgress?: ProgressCallback,\n): Promise<AnalyzedFile[]> {\n onProgress?.('collecting file hashes (batch)...');\n\n // Batch get all file hashes at each ref (one git call per ref)\n const [forkHashes, upstreamHashes, baseHashes] = await Promise.all([\n getFileHashesAtRef(repoPath, localRef),\n getFileHashesAtRef(repoPath, incomingRef),\n getFileHashesAtRef(repoPath, mergeBaseRef),\n ]);\n\n // Get only files that changed between base and incoming (includes renames with -M90%)\n const upstreamChanges = await getFileChanges(repoPath, mergeBaseRef, incomingRef);\n // Get only files that changed between base and local\n const forkChanges = await getFileChanges(repoPath, mergeBaseRef, localRef);\n\n // Build a map of old paths that were renamed in incoming (oldPath -> newPath)\n const upstreamRenames = new Map<string, string>();\n for (const [newPath, change] of upstreamChanges) {\n if (change.status === 'R' && change.oldPath) {\n upstreamRenames.set(change.oldPath, newPath);\n }\n }\n\n // Combined set of all files (for completeness, but we'll only analyze non-identical)\n // Also include old paths from renames to properly track them\n const allFiles = new Set([...forkHashes.keys(), ...upstreamHashes.keys(), ...upstreamRenames.keys()]);\n\n // Files that actually need analysis (changed somewhere)\n const changedFiles = new Set([...upstreamChanges.keys(), ...forkChanges.keys(), ...upstreamRenames.keys()]);\n\n // Content hashes present anywhere in incoming — O(1) rename-source lookups below.\n const upstreamHashSet = new Set(upstreamHashes.values());\n\n onProgress?.(\n `analyzing ${changedFiles.size} changed files (${allFiles.size - changedFiles.size} identical skipped)...`,\n );\n\n const analyzedFiles: AnalyzedFile[] = [];\n // Track old paths that have been handled as part of a rename\n const handledOldPaths = new Set<string>();\n let processed = 0;\n\n for (const filePath of allFiles) {\n // Skip old paths that were already handled as part of a rename\n if (handledOldPaths.has(filePath)) continue;\n\n const inFork = forkHashes.has(filePath);\n const inUpstream = upstreamHashes.has(filePath);\n\n const fileIsIgnored = predicates.isIgnored(filePath);\n const fileIsPinned = predicates.isPinned(filePath);\n\n // Check if this file is the NEW path of an incoming rename\n const upstreamChange = upstreamChanges.get(filePath);\n const isUpstreamRename = upstreamChange?.status === 'R' && upstreamChange.oldPath;\n\n // Check if this file is the OLD path that was renamed in incoming\n const renamedToPath = upstreamRenames.get(filePath);\n\n // Fast path: if file didn't change anywhere, it's identical\n if (!changedFiles.has(filePath) && inFork && inUpstream) {\n analyzedFiles.push({\n path: filePath,\n status: 'identical',\n isIgnored: fileIsIgnored,\n isPinned: fileIsPinned,\n existsInFork: true,\n existsInUpstream: true,\n });\n continue;\n }\n\n processed++;\n if (processed % 100 === 0) {\n onProgress?.(`analyzing ${processed}/${changedFiles.size} changed files...`);\n }\n\n const forkHash = forkHashes.get(filePath) ?? null;\n const upstreamHash = upstreamHashes.get(filePath) ?? null;\n const baseHash = baseHashes.get(filePath) ?? null;\n\n // Determine status\n let status: FileStatus;\n let renamedFrom: string | undefined;\n\n // Handle incoming renames\n if (isUpstreamRename && upstreamChange.oldPath) {\n const oldPath = upstreamChange.oldPath;\n const oldPathInFork = forkHashes.has(oldPath);\n const forkOldHash = forkHashes.get(oldPath) ?? null;\n const baseOldHash = baseHashes.get(oldPath) ?? null;\n\n // Mark the old path as handled so we don't process it separately\n handledOldPaths.add(oldPath);\n\n // Check if local modified the old file\n const forkModifiedOld = forkOldHash !== baseOldHash;\n\n // Check both old and new paths for pinned/ignored status.\n // When a directory is renamed (e.g., config/ → shared/), the local\n // pinned list may still reference the old path.\n const oldPathPinned = predicates.isPinned(oldPath);\n\n if (fileIsPinned || oldPathPinned || predicates.isIgnored(oldPath)) {\n // Pinned or ignored - keep local's version at the new path\n status = 'pinned';\n } else if (!oldPathInFork) {\n // Old path doesn't exist locally (already deleted or moved it)\n // Treat as normal behind - let git's merge handle it\n status = 'behind';\n } else if (forkModifiedOld) {\n // Local modified the old file - this is a diverged situation\n // Let git's merge handle the conflict naturally\n status = 'diverged';\n renamedFrom = oldPath;\n } else {\n // Local has unmodified old file - this is a clean rename to apply\n status = 'renamed';\n renamedFrom = oldPath;\n }\n\n analyzedFiles.push({\n path: filePath,\n status,\n isIgnored: fileIsIgnored,\n isPinned: fileIsPinned,\n existsInFork: inFork,\n existsInUpstream: true,\n renamedFrom,\n });\n continue;\n }\n\n // Skip old paths that were renamed - they'll be handled via the new path\n if (renamedToPath) {\n // This is an old path that incoming renamed - skip it, handled above\n handledOldPaths.add(filePath);\n continue;\n }\n\n if (fileIsIgnored) {\n status = 'ignored';\n } else if (!inFork && inUpstream) {\n // File is missing locally but present in incoming. Distinguish a genuinely new\n // incoming file from a file the local side deliberately deleted, by consulting\n // the merge-base (the symmetric `inFork && !inUpstream` branch does the same):\n // - pinned: local owns the path, keep it removed.\n // - existed at base and incoming hasn't touched it since (upstreamHash === baseHash):\n // the absence is a deliberate local deletion — keep it deleted instead of\n // re-adding it as if incoming introduced a new file (which resurfaces every sync).\n // - otherwise (never in base = truly new, or incoming modified a file the local side\n // deleted = delete/modify): surface incoming's version.\n const locallyDeleted = baseHash !== null && upstreamHash === baseHash;\n status = fileIsPinned || locallyDeleted ? 'deleted' : 'behind';\n } else if (inFork && !inUpstream) {\n // File exists locally but not in incoming\n if (baseHash !== null) {\n // File was in base, incoming deleted it - sync deletion unless pinned\n status = fileIsPinned ? 'ahead' : 'behind';\n } else {\n // Local file (never existed in merge-base). If its exact content exists at a\n // different path in incoming, it is likely the source of a rename we couldn't\n // detect due to a squash merge-base — treat as behind so the rename applies.\n // (This file is absent from incoming, so any hash match is at another path.)\n status = forkHash && upstreamHashSet.has(forkHash) ? 'behind' : 'local';\n }\n } else if (forkHash === upstreamHash) {\n // Identical\n status = 'identical';\n } else {\n // Both exist but different\n const forkChanged = forkHash !== baseHash;\n const upstreamChanged = upstreamHash !== baseHash;\n\n if (forkChanged && upstreamChanged) {\n // Both changed - diverged or pinned conflict\n status = fileIsPinned ? 'pinned' : 'diverged';\n } else if (forkChanged && !upstreamChanged) {\n // Only local changed\n // --hard mode: treat drifted as behind (overwrite with incoming)\n status = fileIsPinned ? 'ahead' : predicates.hard ? 'behind' : 'drifted';\n } else if (!forkChanged && upstreamChanged) {\n // Only incoming changed\n status = 'behind';\n } else {\n // Base is different but local and incoming are same relative to base\n status = 'identical';\n }\n }\n\n analyzedFiles.push({\n path: filePath,\n status,\n isIgnored: fileIsIgnored,\n isPinned: fileIsPinned,\n existsInFork: inFork,\n existsInUpstream: inUpstream,\n });\n }\n\n return analyzedFiles;\n}\n\n/**\n * Enrich analyzed files with change dates and commit hashes.\n *\n * Mutates each non-identical file in place: local-side dates for ahead/drifted,\n * incoming-side dates for behind, and both sides for diverged/pinned.\n *\n * @param repoPath - Repo where the refs are reachable\n * @param files - Files to enrich (mutated in place)\n * @param mergeBaseRef - Common ancestor ref\n * @param localRef - The \"ours\" ref\n * @param incomingRef - The \"theirs\" ref\n */\nexport async function enrichChangeInfo(\n repoPath: string,\n files: AnalyzedFile[],\n mergeBaseRef: string,\n localRef: string,\n incomingRef: string,\n): Promise<void> {\n const forkInfo = await getFileChangeInfo(repoPath, mergeBaseRef, localRef);\n const upstreamInfo = await getFileChangeInfo(repoPath, mergeBaseRef, incomingRef);\n\n for (const file of files) {\n if (file.status === 'identical') continue;\n\n if (file.status === 'ahead' || file.status === 'drifted') {\n const info = forkInfo.get(file.path);\n if (info) {\n file.changedAt = info.date;\n file.changedTs = info.timestamp;\n file.changedCommit = info.hash;\n }\n } else if (file.status === 'behind') {\n const info = upstreamInfo.get(file.path);\n if (info) {\n file.changedAt = info.date;\n file.changedTs = info.timestamp;\n file.changedCommit = info.hash;\n }\n } else if (file.status === 'diverged' || file.status === 'pinned') {\n // For diverged/pinned: store both local and incoming info\n const forkFileInfo = forkInfo.get(file.path);\n const upstreamFileInfo = upstreamInfo.get(file.path);\n if (forkFileInfo) {\n file.changedAt = forkFileInfo.date;\n file.changedTs = forkFileInfo.timestamp;\n file.changedCommit = forkFileInfo.hash;\n }\n if (upstreamFileInfo) {\n file.upstreamChangedAt = upstreamFileInfo.date;\n file.upstreamChangedTs = upstreamFileInfo.timestamp;\n file.upstreamCommit = upstreamFileInfo.hash;\n }\n }\n }\n}\n","/**\n * Merge Engine for sync CLI v2.\n *\n * Two modes:\n * - Analyze (dry run): Uses worktree to preview changes without affecting fork\n * - Sync: Performs real merge directly in fork for full IDE support\n *\n * Sync mode approach:\n * 1. Start real merge in fork (git merge --no-commit)\n * 2. Apply resolutions directly (pinned→ours, ignored→rm, diverged→git's merge)\n * 3. Leave fork in merge state - conflicts have markers for IDE 3-way merge\n *\n * Key principle: Fork stays in real merge state for IDE conflict resolution.\n */\n\nimport type { AnalysisSummary, AnalyzedFile, MergeResult, RuntimeConfig } from '../config/types';\nimport { cleanupLeftoverWorktrees, cleanupWorktree, getWorktreePath, registerWorktree } from '../utils/cleanup';\nimport { DEFAULT_UPSTREAM_REMOTE, resolveUpstream } from '../utils/config';\nimport { formatFetchedUpstreamDetail, formatMergeInProgressDetail } from '../utils/display';\nimport {\n batchGitRm,\n batchRestoreToHead,\n batchUnstageFiles,\n type CommitRangeEntry,\n checkoutFromRef,\n countCommitsBetween,\n createWorktree,\n ensureRemote,\n ensureSyncBase,\n fetch,\n fetchUpstreamTags,\n fileExistsAtRef,\n fileExistsInWorktree,\n getCommitInfo,\n getConflictedFiles,\n getCurrentBranch,\n getEffectiveMergeBase,\n getMergeBase,\n getShortSha,\n getStagedNewFiles,\n getUpstreamStatus,\n getWorkingTreeChangeCount,\n gitMv,\n listCommitsBetween,\n merge,\n mergeAbort,\n removeFileFromWorktree,\n removeFileFully,\n resolveLatestReleaseTag,\n restoreToHead,\n stagePath,\n storeLastSyncRef,\n withTemporarySyncBaseGraft,\n} from '../utils/git';\nimport { isManagedFile } from '../utils/managed-files';\nimport { MANIFEST_FILE, type SyncManifest, writeSyncManifest } from '../utils/manifest';\nimport { isIgnored, isPinnedForSync } from '../utils/overrides';\nimport { type AnalyzePredicates, analyzeRefs, enrichChangeInfo } from './analyze-core';\n\n/** Progress callback type - receives message and optional detail for sub-line */\ntype ProgressCallback = (message: string, detail?: string) => void;\n\n/** Step completion callback - marks a step as done with optional detail */\ntype StepCallback = (label: string, detail?: string) => void;\n\n/**\n * Convert a git remote URL to a GitHub base URL.\n * Supports both SSH (git@github.com:org/repo.git) and HTTPS formats.\n */\nfunction getGitHubBaseUrl(remoteUrl: string): string | null {\n // SSH format: git@github.com:cellajs/cella.git\n const sshMatch = remoteUrl.match(/git@github\\.com:([^/]+)\\/([^.]+)(?:\\.git)?$/);\n if (sshMatch) {\n return `https://github.com/${sshMatch[1]}/${sshMatch[2]}`;\n }\n\n // HTTPS format: https://github.com/cellajs/cella.git\n const httpsMatch = remoteUrl.match(/https:\\/\\/github\\.com\\/([^/]+)\\/([^/.]+)(?:\\.git)?$/);\n if (httpsMatch) {\n return `https://github.com/${httpsMatch[1]}/${httpsMatch[2]}`;\n }\n\n return null;\n}\n\n/** Build analyzer predicates for the sync direction (local = fork, incoming = upstream). */\nfunction syncPredicates(config: RuntimeConfig): AnalyzePredicates {\n return {\n isIgnored: (path) => isIgnored(path, config),\n isPinned: (path) => isPinnedForSync(path, config, config.unpinned),\n hard: config.hard,\n };\n}\n\n/**\n * Apply merge directly to fork with pre-analysis.\n *\n * Strategy: analyze BEFORE merge (uses git refs only, invisible to IDE),\n * then merge + immediate batch resolution to minimize working tree flickering.\n *\n * 1. Pre-analyze using git refs (no working tree changes)\n * 2. Collect batch resolution plan (which files to restore/remove)\n * 3. Start real merge in fork (git merge --no-commit)\n * 4. Immediately batch-restore pinned/ignored files (single git command)\n * 5. Apply remaining individual resolutions\n * 6. Leave fork in merge state for IDE 3-way conflict resolution\n */\nasync function applyDirectMerge(\n forkPath: string,\n upstreamRef: string,\n mergeBaseRef: string,\n config: RuntimeConfig,\n onProgress?: ProgressCallback,\n): Promise<{\n remainingConflicts: string[];\n analyzedFiles: AnalyzedFile[];\n autoMergedFiles: string[];\n}> {\n // Phase 1: Pre-analyze using git refs (invisible to IDE).\n // analyzeRefs only uses git plumbing (ls-tree, diff-tree) on refs,\n // not the working tree, so results are identical before or after merge.\n onProgress?.('analyzing files...');\n const analyzedFiles = await analyzeRefs(\n forkPath,\n 'HEAD',\n upstreamRef,\n mergeBaseRef,\n syncPredicates(config),\n onProgress,\n );\n\n // Phase 2: Collect batch resolution plan for immediate post-merge application.\n // These files will be restored to HEAD in a single git command right after merge,\n // preventing the IDE from seeing upstream changes to pinned/ignored files.\n const batchRestorePaths: string[] = [];\n const batchRemovePaths: string[] = [];\n\n for (const file of analyzedFiles) {\n const { path: filePath, status, isPinned: pinned, isIgnored: ignored, existsInFork } = file;\n if (status === 'identical' || status === 'ahead') continue;\n\n if (ignored && existsInFork) {\n batchRestorePaths.push(filePath);\n } else if (ignored && !existsInFork) {\n batchRemovePaths.push(filePath);\n } else if (pinned && !file.renamedFrom && existsInFork) {\n batchRestorePaths.push(filePath);\n } else if (pinned && !file.renamedFrom && !existsInFork) {\n // Pinned file doesn't exist in fork — remove from merge to keep fork's state (deleted)\n batchRemovePaths.push(filePath);\n }\n }\n\n // Phase 3: Start real merge in fork. Left staged with MERGE_HEAD intact so git and the IDE\n // treat it as a real in-progress merge (3-way conflict view, `git merge --abort` works).\n // The finishing rerun squashes the commit to a single parent (`commitSquash`) — upstream\n // ancestry is tracked via the manifest, never via a pushed two-parent merge commit.\n // The temporary graft makes the merge 3-way against the recorded sync point instead of\n // git's own (squash-stale) merge-base — without it, upstream hunks already integrated by\n // previous syncs re-apply or re-conflict on every run.\n onProgress?.('starting merge in fork...');\n await withTemporarySyncBaseGraft(forkPath, 'HEAD', mergeBaseRef, () =>\n merge(forkPath, upstreamRef, { noCommit: true, noEdit: true }),\n );\n\n // Phase 4: Immediately batch-restore pinned/ignored files.\n // Single git command restores all files at once, minimizing the window\n // where the IDE sees upstream changes to protected files.\n if (batchRestorePaths.length > 0) {\n onProgress?.(`batch restoring ${batchRestorePaths.length} pinned/ignored files...`);\n await batchRestoreToHead(forkPath, batchRestorePaths);\n }\n if (batchRemovePaths.length > 0) {\n onProgress?.(`batch removing ${batchRemovePaths.length} ignored files...`);\n await batchGitRm(forkPath, batchRemovePaths);\n for (const filePath of batchRemovePaths) {\n await removeFileFromWorktree(forkPath, filePath);\n }\n }\n\n // Phase 5: Apply remaining individual resolutions.\n // Pinned/ignored already handled in batch above — skip them here.\n for (const file of analyzedFiles) {\n const { path: filePath, status, isPinned: pinned, isIgnored: ignored, existsInFork } = file;\n\n if (status === 'identical' || status === 'ahead') {\n continue;\n }\n\n // Skip files already handled in batch\n if (ignored) continue;\n if (pinned && !file.renamedFrom) continue;\n\n if (pinned && file.renamedFrom) {\n // Renamed file where old path was pinned — accept the rename (new path)\n // but keep fork's content from the old path\n const oldPathExists = await fileExistsInWorktree(forkPath, file.renamedFrom);\n if (oldPathExists) {\n onProgress?.(`→ ${file.renamedFrom} → ${filePath}: moving fork content (pinned rename)`);\n try {\n await gitMv(forkPath, file.renamedFrom, filePath);\n } catch {\n // git mv failed — copy content manually\n await removeFileFully(forkPath, file.renamedFrom);\n // Checkout upstream's new path first, then restore fork content\n await checkoutFromRef(forkPath, 'HEAD', file.renamedFrom).catch(() => {});\n }\n } else {\n // Old path already gone — restore from HEAD at old path via git show\n onProgress?.(`→ ${filePath}: keeping fork content (pinned rename, old path removed)`);\n await restoreToHead(forkPath, filePath);\n }\n continue;\n }\n\n if (status === 'diverged') {\n // Let git's merge result stand - trust the merge\n onProgress?.(`→ ${filePath}: using git merge result (diverged)`);\n continue;\n }\n\n if (status === 'behind') {\n // File only in upstream or upstream has newer version\n if (!existsInFork) {\n // Upstream added new file\n onProgress?.(`→ ${filePath}: adding from upstream (new file)`);\n await checkoutFromRef(forkPath, upstreamRef, filePath);\n } else if (!file.existsInUpstream) {\n // Upstream deleted file - remove from fork (including leftovers after squash merge)\n onProgress?.(`→ ${filePath}: removing (deleted in upstream)`);\n await removeFileFully(forkPath, filePath);\n } else {\n // Both exist, only upstream changed - accept upstream version explicitly.\n // This resolves false conflicts from stale merge-base (previous squash syncs).\n onProgress?.(`→ ${filePath}: accepting upstream (behind)`);\n await checkoutFromRef(forkPath, upstreamRef, filePath);\n }\n continue;\n }\n\n if (status === 'deleted') {\n await removeFileFully(forkPath, filePath);\n continue;\n }\n\n if (status === 'renamed' && file.renamedFrom) {\n // Upstream renamed a file - apply as git mv to preserve history\n const oldPath = file.renamedFrom;\n const oldPathExists = await fileExistsInWorktree(forkPath, oldPath);\n const newPathExists = await fileExistsInWorktree(forkPath, filePath);\n\n if (oldPathExists && !newPathExists) {\n // Old exists, new doesn't - use git mv to move the file, preserving history\n onProgress?.(`→ ${oldPath} → ${filePath}: moving (renamed in upstream)`);\n try {\n await gitMv(forkPath, oldPath, filePath);\n } catch {\n // git mv failed (possibly due to merge state) - fall back to manual approach\n await removeFileFully(forkPath, oldPath);\n await checkoutFromRef(forkPath, upstreamRef, filePath);\n }\n } else if (oldPathExists && newPathExists) {\n // Both exist (merge already staged the new file, but old still in worktree)\n // Remove old and ensure new has correct content\n onProgress?.(`→ ${oldPath} → ${filePath}: completing rename (removing old)`);\n await removeFileFully(forkPath, oldPath);\n await checkoutFromRef(forkPath, upstreamRef, filePath);\n } else {\n // Rename already applied (or neither path exists) - ensure new path has upstream content\n onProgress?.(`→ ${filePath}: updating from upstream (renamed)`);\n await checkoutFromRef(forkPath, upstreamRef, filePath);\n }\n }\n }\n\n // Handle remaining git conflicts: auto-resolve only ignored/pinned (fork wins);\n // everything else keeps its markers for IDE 3-way resolution.\n const gitConflicts = await getConflictedFiles(forkPath);\n for (const filePath of gitConflicts) {\n const isProtected = isIgnored(filePath, config) || isPinnedForSync(filePath, config, config.unpinned);\n if (!isProtected) continue;\n\n if (await fileExistsAtRef(forkPath, 'HEAD', filePath)) {\n onProgress?.(`→ ${filePath}: keeping fork (protected conflict)`);\n await restoreToHead(forkPath, filePath);\n } else {\n onProgress?.(`→ ${filePath}: removing (protected conflict, not in fork)`);\n await removeFileFully(forkPath, filePath);\n }\n }\n\n // Get remaining conflicts (these have markers for IDE)\n const remainingConflicts = await getConflictedFiles(forkPath);\n const remainingConflictSet = new Set(remainingConflicts);\n const autoMergedFiles = analyzedFiles\n .filter((file) => file.status === 'diverged' && !remainingConflictSet.has(file.path))\n .map((file) => file.path);\n\n // Phase 6: Safety net — clean up any ignored files still staged after merge.\n // During a merge, batchGitRm can silently fail on newly-added files, leaving\n // them as \"Added in index, Deleted from working tree\" (AD status). This catches\n // any ignored files that slipped through the earlier resolution phases.\n const stagedNewFiles = await getStagedNewFiles(forkPath);\n const staleIgnoredFiles = stagedNewFiles.filter((f) => isIgnored(f, config));\n if (staleIgnoredFiles.length > 0) {\n onProgress?.(`cleaning up ${staleIgnoredFiles.length} ignored files still in index...`);\n await batchUnstageFiles(forkPath, staleIgnoredFiles);\n for (const filePath of staleIgnoredFiles) {\n await removeFileFromWorktree(forkPath, filePath);\n }\n }\n\n return { remainingConflicts, analyzedFiles, autoMergedFiles };\n}\n\n/**\n * Calculate summary from analyzed files.\n */\nfunction calculateSummary(files: AnalyzedFile[]): AnalysisSummary {\n const summary: AnalysisSummary = {\n managed: 0,\n identical: 0,\n ahead: 0,\n local: 0,\n drifted: 0,\n behind: 0,\n diverged: 0,\n pinned: 0,\n ignored: 0,\n deleted: 0,\n renamed: 0,\n total: files.length,\n };\n\n for (const file of files) {\n if (file.status !== 'identical' && isManagedFile(file.path)) {\n summary.managed++;\n continue;\n }\n\n summary[file.status]++;\n }\n\n return summary;\n}\n\n/**\n * Upstream context resolved once per run and shared by both engine modes.\n */\ninterface UpstreamContext {\n /** Concrete upstream ref merged from (branch tip or release-tag ref) */\n upstreamRef: string;\n /** Release tag when tracking releases */\n releaseTag?: string;\n /** Effective merge-base used for the 3-way analysis */\n mergeBase: string;\n /** Upstream GitHub URL base for commit links */\n upstreamGitHubUrl?: string;\n /** Upstream HEAD commit info */\n upstreamCommit: { hash: string; message: string; date: string };\n /** Commits included in this sync range (oldest-first) */\n upstreamCommits: CommitRangeEntry[];\n}\n\nfunction formatLocalCheckoutDetail(\n forkPath: string,\n branch: string,\n headSha: string,\n changeCount: number,\n upstream: { upstream: string | null; ahead: number; behind: number },\n): string {\n const tracking = upstream.upstream\n ? `, tracking ${upstream.upstream} (${upstream.ahead} ahead, ${upstream.behind} behind)`\n : ', no tracking branch';\n const workingTree =\n changeCount === 0\n ? ' working tree clean'\n : ` ${changeCount} uncommitted change${changeCount === 1 ? '' : 's'} in working tree, not included in analysis`;\n\n return [`${forkPath}`, ` ${branch} @ ${headSha}${tracking}`, workingTree].join('\\n');\n}\n\n/**\n * Resolve everything both modes need from upstream: remote setup, the concrete\n * ref to merge (branch tip or latest release tag), sync ancestry bootstrap,\n * effective merge-base, and commit info for progress output.\n */\nasync function prepareUpstream(\n config: RuntimeConfig,\n onProgress?: ProgressCallback,\n onStep?: StepCallback,\n): Promise<UpstreamContext> {\n const { forkPath } = config;\n\n onProgress?.('checking local checkout...');\n const [branch, headSha, changeCount, upstreamStatus] = await Promise.all([\n getCurrentBranch(forkPath),\n getShortSha(forkPath, 'HEAD'),\n getWorkingTreeChangeCount(forkPath),\n getUpstreamStatus(forkPath),\n ]);\n onStep?.('local checkout', formatLocalCheckoutDetail(forkPath, branch, headSha, changeCount, upstreamStatus));\n\n // Setup upstream remote\n onProgress?.('setting up upstream remote...');\n const { track: configTrack, branchRef } = resolveUpstream(config.settings);\n const remoteName = DEFAULT_UPSTREAM_REMOTE;\n // A per-run --track flag (config.track) overrides the configured tracking mode.\n const track = config.track ?? configTrack;\n await ensureRemote(forkPath, remoteName, config.settings.upstreamUrl);\n\n // Fetch upstream (branches, plus release tags into a fork-safe namespace).\n onProgress?.(`fetching upstream (${remoteName})...`);\n await fetch(forkPath, remoteName);\n\n // Resolve the concrete ref to merge from. Release tracking (default) syncs to the\n // latest published release tag; branch tracking follows the upstream branch tip.\n let upstreamRef = branchRef;\n let releaseTag: string | undefined;\n if (track === 'release') {\n await fetchUpstreamTags(forkPath, remoteName);\n const latest = await resolveLatestReleaseTag(forkPath, remoteName);\n if (!latest) {\n throw new Error(\n `no upstream releases (v*) found on '${remoteName}'. Set upstreamTrack: 'branch' to follow ${branchRef}, ` +\n `or check that ${config.settings.upstreamUrl} publishes release tags.`,\n );\n }\n upstreamRef = latest.ref;\n releaseTag = latest.tag;\n }\n\n // Expose the resolved ref to downstream steps (packages/analyze read config.upstreamRef\n // after the engine runs). The static fallback set at CLI parse time is the branch tip.\n config.upstreamRef = upstreamRef;\n onStep?.('remote configured', `${releaseTag ?? upstreamRef} → ${config.settings.upstreamUrl}`);\n\n // Bootstrap sync ancestry for forks with unrelated history (create-cella scaffold or an\n // upstream history squash). No-op once a native merge-base exists. Runs after fetch so the\n // base commit object is present, and after upstreamRef is finalized so release tags resolve.\n onProgress?.('checking sync base...');\n await ensureSyncBase(forkPath, 'HEAD', upstreamRef);\n\n const upstreamGitHubUrl = getGitHubBaseUrl(config.settings.upstreamUrl) ?? undefined;\n\n // Get effective merge base (handles stale base from previous squash syncs).\n // --hard and --unpinned use the natural merge-base instead, resurfacing the\n // full upstream history so previously-hidden drift/pins reappear consistently.\n const aggressive = config.hard === true || config.unpinned === true;\n const mergeBase = aggressive\n ? await getMergeBase(forkPath, 'HEAD', upstreamRef)\n : (await getEffectiveMergeBase(forkPath, 'HEAD', upstreamRef)).base;\n\n // Get upstream commit info and count commits since merge-base\n const upstreamCommit = await getCommitInfo(forkPath, upstreamRef);\n const commitCount = await countCommitsBetween(forkPath, mergeBase, upstreamRef);\n const commitListMax = 50;\n const commitSkip = commitCount > commitListMax ? commitCount - commitListMax : 0;\n const upstreamCommits =\n commitCount > 0\n ? await listCommitsBetween(forkPath, mergeBase, upstreamRef, {\n oldestFirst: true,\n skip: commitSkip,\n limit: commitListMax,\n })\n : [];\n\n onStep?.('fetched upstream', formatFetchedUpstreamDetail(commitCount, upstreamCommits, upstreamGitHubUrl));\n\n return { upstreamRef, releaseTag, mergeBase, upstreamGitHubUrl, upstreamCommit, upstreamCommits };\n}\n\n/** MergeResult fields shared by both engine modes. */\nfunction resultMeta(config: RuntimeConfig, ctx: UpstreamContext) {\n return {\n upstreamBranch: config.settings.upstreamBranch ?? 'main',\n upstreamRef: ctx.upstreamRef,\n upstreamTag: ctx.releaseTag,\n upstreamGitHubUrl: ctx.upstreamGitHubUrl,\n upstreamCommit: ctx.upstreamCommit,\n upstreamCommits: ctx.upstreamCommits,\n };\n}\n\n/**\n * SYNC MODE: merge, analyze, and resolve directly in the fork, then record the\n * sync point (local ref + committed manifest) and leave the merge staged.\n */\nasync function runSyncMerge(\n config: RuntimeConfig,\n ctx: UpstreamContext,\n onProgress?: ProgressCallback,\n onStep?: StepCallback,\n): Promise<MergeResult> {\n const { forkPath } = config;\n const { upstreamRef, releaseTag, mergeBase, upstreamGitHubUrl, upstreamCommit } = ctx;\n\n const { remainingConflicts, analyzedFiles, autoMergedFiles } = await applyDirectMerge(\n forkPath,\n upstreamRef,\n mergeBase,\n config,\n onProgress,\n );\n\n const summary = calculateSummary(analyzedFiles);\n const synced = analyzedFiles.filter((file) => ['behind', 'diverged', 'renamed'].includes(file.status)).length;\n\n // Count total resolved changes (includes ignored/pinned resolutions)\n const totalResolved = analyzedFiles.filter((file) =>\n ['behind', 'diverged', 'renamed', 'ignored', 'pinned'].includes(file.status),\n ).length;\n\n // Record the upstream sync point in lockstep: the local `refs/cella/last-sync` ref plus\n // the committed `cella.manifest.json` (staged so it rides in the sync commit and travels\n // with the repo for fresh-clone bootstrap).\n const syncManifest: SyncManifest = {\n upstream: {\n repo: upstreamGitHubUrl ? upstreamGitHubUrl.replace('https://github.com/', '') : undefined,\n track: releaseTag ? 'release' : 'branch',\n commit: upstreamCommit.hash,\n release: releaseTag ?? null,\n url: upstreamGitHubUrl\n ? releaseTag\n ? `${upstreamGitHubUrl}/releases/tag/${releaseTag}`\n : `${upstreamGitHubUrl}/commit/${upstreamCommit.hash}`\n : undefined,\n syncedAt: new Date().toISOString(),\n },\n };\n const recordSyncPoint = async () => {\n await storeLastSyncRef(forkPath, upstreamCommit.hash);\n await writeSyncManifest(forkPath, syncManifest);\n await stagePath(forkPath, MANIFEST_FILE);\n };\n\n if (remainingConflicts.length > 0) {\n // Conflicts: leave MERGE_HEAD intact for IDE 3-way merge resolution. The finishing\n // `cella sync` rerun commits single-parent (`commitSquash`); if the user commits manually\n // instead, the resulting merge commit is flattened away before the branch is pushed\n // (`flattenSyncBranch`) so the PR never lists the whole upstream history.\n await recordSyncPoint();\n onStep?.(\n 'merge in progress',\n formatMergeInProgressDetail(remainingConflicts.length, autoMergedFiles, { forkPath }, 100),\n );\n } else if (totalResolved > 0) {\n const label = synced > 0 ? `${synced} files from upstream` : 'upstream changes';\n // Keep MERGE_HEAD so the finishing rerun can tell a staged sync from a plain dirty\n // tree (`mergeInProgress`) and `git merge --abort` still works. The commit itself is\n // made single-parent at commit time (`commitSquash`).\n await recordSyncPoint();\n onStep?.('synced', `${label} (staged, commit to finish)`);\n } else {\n // Truly nothing changed - clean up merge state\n await mergeAbort(forkPath);\n onStep?.('up to date', 'no upstream changes to sync');\n }\n\n return {\n success: remainingConflicts.length === 0,\n files: analyzedFiles,\n summary,\n conflicts: remainingConflicts,\n autoMergedFiles,\n ...resultMeta(config, ctx),\n };\n}\n\n/**\n * ANALYZE MODE: preview the merge in a temp worktree (invisible to the IDE),\n * classify all files, and discard the worktree — the fork is never touched.\n */\nasync function runAnalyzePreview(\n config: RuntimeConfig,\n ctx: UpstreamContext,\n onProgress?: ProgressCallback,\n onStep?: StepCallback,\n): Promise<MergeResult> {\n const { forkPath } = config;\n const worktreePath = getWorktreePath(forkPath);\n\n // Create worktree in temp directory (invisible to VSCode)\n onProgress?.('creating worktree in temp directory...');\n await createWorktree(forkPath, worktreePath, 'HEAD');\n onStep?.('worktree created', worktreePath);\n\n // Perform merge in worktree (always real merge, never --squash, for correct 3-way).\n // Replace refs are shared across worktrees, so the temporary graft on the fork's HEAD\n // commit steers this worktree merge to the recorded sync point too.\n onProgress?.('performing merge in worktree...');\n await withTemporarySyncBaseGraft(worktreePath, 'HEAD', ctx.mergeBase, () =>\n merge(worktreePath, ctx.upstreamRef, { noCommit: true, noEdit: true }),\n );\n onStep?.('merge complete', 'upstream merged into worktree');\n\n // Analyze all files, then enrich with change dates and commit hashes\n onProgress?.('analyzing files...');\n const analyzedFiles = await analyzeRefs(\n forkPath,\n 'HEAD',\n ctx.upstreamRef,\n ctx.mergeBase,\n syncPredicates(config),\n onProgress,\n );\n await enrichChangeInfo(forkPath, analyzedFiles, ctx.mergeBase, 'HEAD', ctx.upstreamRef);\n onStep?.('analysis complete', `${analyzedFiles.length} files analyzed, dry run — no changes applied`);\n\n onProgress?.('cleaning up worktree...');\n await cleanupWorktree(forkPath, worktreePath);\n\n return {\n success: true,\n files: analyzedFiles,\n summary: calculateSummary(analyzedFiles),\n // For analyze mode, count diverged files as potential conflicts\n conflicts: analyzedFiles.filter((f) => f.status === 'diverged').map((f) => f.path),\n ...resultMeta(config, ctx),\n };\n}\n\n/**\n * Main merge engine entry point: prepare upstream once, then run the requested mode.\n */\nexport async function runMergeEngine(\n config: RuntimeConfig,\n options: {\n apply: boolean;\n onProgress?: ProgressCallback;\n onStep?: StepCallback;\n },\n): Promise<MergeResult> {\n const { forkPath } = config;\n const worktreePath = getWorktreePath(forkPath);\n const { apply, onProgress, onStep } = options;\n\n // Clean up any leftover worktree from a previous interrupted run\n await cleanupLeftoverWorktrees(forkPath);\n\n // Register worktree for cleanup on abort\n registerWorktree(forkPath, worktreePath);\n\n try {\n const ctx = await prepareUpstream(config, onProgress, onStep);\n return apply\n ? await runSyncMerge(config, ctx, onProgress, onStep)\n : await runAnalyzePreview(config, ctx, onProgress, onStep);\n } catch (error) {\n // Clean up on error\n await cleanupWorktree(forkPath, worktreePath);\n throw error;\n }\n}\n","/**\n * Audit service for the Cella CLI.\n *\n * Checks for outdated packages and security vulnerabilities across the monorepo.\n */\n\nimport { spawnSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { checkbox, confirm, Separator } from '@inquirer/prompts';\nimport type { RuntimeConfig } from '../config/types';\nimport {\n type AuditResult,\n buildVulnerabilityMap,\n clearCache,\n type EnhancedPackageInfo,\n fetchNpmMetadata,\n findChangelogUrl,\n formatDependents,\n getHighestSeverity,\n getOutdatedPackages,\n getReleasesUrl,\n getRepoUrl,\n getVulnIcon,\n isMajorVersionChange,\n loadCache,\n middleTruncate,\n runPnpmAudit,\n saveCache,\n type VulnerabilityInfo,\n} from '../utils/audit-utils';\nimport pc from '../utils/colors';\nimport { createSpinner, hyperlink, spinnerSuccess, spinnerText, warningMark } from '../utils/display';\nimport { parseYamlBlockMap } from '../utils/yaml';\n\n/** Options for the audit service */\ninterface AuditOptions {\n /** Whether to bypass pnpm metadata cache for fresh registry data */\n force?: boolean;\n /** Whether to check which pnpm.overrides are still needed */\n checkOverrides?: boolean;\n}\n\n/**\n * Audit service - checks for outdated packages and security vulnerabilities.\n */\nexport async function runAudit(config: RuntimeConfig, options: AuditOptions = {}): Promise<void> {\n const { forkPath } = config;\n\n // Handle check-overrides mode\n if (options.checkOverrides) {\n await checkOverrides(forkPath);\n return;\n }\n\n const spinner = createSpinner('checking for outdated packages & vulnerabilities...');\n try {\n // Clear pnpm metadata cache when force is set to get fresh registry data\n if (options.force) {\n spinnerText('clearing pnpm metadata cache...');\n clearCache();\n spawnSync('pnpm', ['cache', 'delete', '*'], {\n cwd: forkPath,\n stdio: 'ignore',\n });\n spinnerText('checking for outdated packages & vulnerabilities...');\n }\n\n // Run outdated check and audit in parallel\n const [outdatedPackages, auditResult] = await Promise.all([getOutdatedPackages(forkPath), runPnpmAudit(forkPath)]);\n\n const packageNames = Object.keys(outdatedPackages);\n const vulnMap = buildVulnerabilityMap(auditResult);\n\n if (packageNames.length === 0 && vulnMap.size === 0) {\n spinnerSuccess('all packages are up to date and secure');\n return;\n }\n\n // Load cache for changelog URLs\n const cache = loadCache();\n\n spinnerText(`found ${packageNames.length} outdated package(s) - fetching metadata...`);\n\n // Read each dependent's package.json once; used for display names and pin detection.\n type DependentPkgJson = { name?: string } & Partial<\n Record<'dependencies' | 'devDependencies', Record<string, string>>\n >;\n const pkgJsonCache = new Map<string, DependentPkgJson | null>();\n const readDependentPkg = (location: string): DependentPkgJson | null => {\n let cached = pkgJsonCache.get(location);\n if (cached === undefined) {\n try {\n cached = JSON.parse(fs.readFileSync(path.join(location, 'package.json'), 'utf-8'));\n } catch {\n cached = null;\n }\n pkgJsonCache.set(location, cached ?? null);\n }\n return cached ?? null;\n };\n\n const dependentNameCache = new Map<string, string>();\n for (const name of packageNames) {\n for (const dep of outdatedPackages[name].dependentPackages) {\n if (!dependentNameCache.has(dep.location)) {\n dependentNameCache.set(dep.location, readDependentPkg(dep.location)?.name || path.basename(dep.location));\n }\n }\n }\n\n // Fetch metadata for all packages in parallel (with concurrency limit)\n const enhancedPackages: EnhancedPackageInfo[] = [];\n const batchSize = 10;\n\n for (let i = 0; i < packageNames.length; i += batchSize) {\n const batch = packageNames.slice(i, i + batchSize);\n const results = await Promise.all(\n batch.map(async (name) => {\n const pkg = outdatedPackages[name];\n const metadata = await fetchNpmMetadata(name);\n const repoUrl = getRepoUrl(metadata);\n const changelogUrl = await findChangelogUrl(repoUrl, name, cache);\n\n // Detect workspaces where this package is pinned (exact version, no ^ or ~)\n const pinnedIn: string[] = [];\n for (const d of pkg.dependentPackages) {\n const spec = readDependentPkg(d.location)?.[pkg.dependencyType]?.[name] || '';\n if (spec && !spec.startsWith('^') && !spec.startsWith('~') && !spec.startsWith('>')) {\n pinnedIn.push(d.name);\n }\n }\n\n return {\n name,\n current: pkg.current,\n latest: pkg.latest,\n dependents: pkg.dependentPackages.map((d) => d.name),\n dependentLocations: pkg.dependentPackages.map((d) => d.location),\n isDev: pkg.dependencyType === 'devDependencies',\n isMajorUpdate: isMajorVersionChange(pkg.current, pkg.latest),\n pinnedIn,\n repoUrl,\n changelogUrl,\n releasesUrl: getReleasesUrl(repoUrl),\n vulnerabilities: vulnMap.get(name) || [],\n };\n }),\n );\n enhancedPackages.push(...results);\n }\n\n // Save updated cache\n saveCache(cache);\n\n // Sort: by dependents (primary), then alphabetically (secondary)\n enhancedPackages.sort((a, b) => {\n const depA = formatDependents(a.dependents);\n const depB = formatDependents(b.dependents);\n const depCompare = depA.localeCompare(depB);\n if (depCompare !== 0) return depCompare;\n return a.name.localeCompare(b.name);\n });\n\n spinner.stop();\n\n // Print results\n if (enhancedPackages.length > 0) {\n printOutdatedResults(enhancedPackages, dependentNameCache, forkPath);\n }\n printVulnerabilityResults(auditResult, vulnMap);\n\n // Interactive update prompt (skip in non-interactive/list mode)\n // Show when there are outdated packages OR vulnerabilities to fix\n const hasVulns = vulnMap.size > 0;\n if ((enhancedPackages.length > 0 || hasVulns) && !config.list) {\n await promptForUpdates(enhancedPackages, forkPath, auditResult);\n }\n } finally {\n spinner.stop();\n }\n}\n\n/**\n * Print outdated packages results table.\n */\nfunction printOutdatedResults(\n enhancedPackages: EnhancedPackageInfo[],\n dependentNameCache: Map<string, string>,\n forkPath: string,\n): void {\n // Calculate column widths\n const DEV_TAG = ' (dev)';\n const MAX_NAME_LEN = 35;\n const MAX_DEPENDENTS_LEN = 15;\n const maxNameLen = Math.min(\n MAX_NAME_LEN,\n Math.max(7, ...enhancedPackages.map((p) => p.name.length + (p.isDev ? DEV_TAG.length : 0))),\n );\n const maxCurrentLen = Math.max(7, ...enhancedPackages.map((p) => p.current.length));\n const maxLatestLen = Math.max(6, ...enhancedPackages.map((p) => p.latest.length));\n const maxDependentsLen = Math.min(\n MAX_DEPENDENTS_LEN,\n Math.max(10, ...enhancedPackages.map((p) => formatDependents(p.dependents).length)),\n );\n\n // Header (vuln column is just a dot, so minimal width)\n const header = [\n ' ',\n pc.bold('package'.padEnd(maxNameLen)),\n pc.bold('current'.padEnd(maxCurrentLen)),\n pc.bold('latest'.padEnd(maxLatestLen)),\n pc.bold('in'.padEnd(maxDependentsLen)),\n pc.bold('links'),\n ].join(' ');\n\n console.info(header);\n\n // Rows\n for (const pkg of enhancedPackages) {\n // Vulnerability indicator\n const highestSeverity = getHighestSeverity(pkg.vulnerabilities);\n const vulnIndicator = highestSeverity ? getVulnIcon(highestSeverity) : ' ';\n\n // Package name (with dev tag, truncated if needed)\n const fullName = pkg.isDev ? `${pkg.name}${DEV_TAG}` : pkg.name;\n const displayName = middleTruncate(fullName, maxNameLen);\n const name = pc.white(displayName.padEnd(maxNameLen));\n\n // Version columns\n const current = pc.red(pkg.current.padEnd(maxCurrentLen));\n const latestText = pkg.latest.padEnd(maxLatestLen);\n const latest = pkg.isMajorUpdate ? pc.bold(pc.green(latestText)) : pc.green(latestText);\n\n // Dependents (compact format)\n const dependentsText = formatDependents(pkg.dependents);\n const dependents = pc.dim(middleTruncate(dependentsText, maxDependentsLen).padEnd(maxDependentsLen));\n\n // Build links (compact)\n const links: string[] = [];\n if (pkg.changelogUrl) {\n links.push(hyperlink(pc.magenta('log'), pkg.changelogUrl));\n }\n if (pkg.releasesUrl) {\n links.push(hyperlink(pc.blue('rel'), pkg.releasesUrl));\n }\n if (pkg.repoUrl) {\n links.push(hyperlink(pc.cyan('repo'), pkg.repoUrl));\n }\n\n const linksStr = links.length > 0 ? links.join(' ') : pc.dim('n/a');\n\n console.info(`${vulnIndicator} ${name} ${current} ${latest} ${dependents} ${linksStr}`);\n }\n\n // Package.json links with counts by dependent name\n console.info();\n // Build map of dependent name -> { location, count } using pre-cached names\n const dependentMap = new Map<string, { location: string; count: number }>();\n for (const pkg of enhancedPackages) {\n for (const loc of pkg.dependentLocations) {\n const dependentName = dependentNameCache.get(loc) || path.basename(loc);\n const existing = dependentMap.get(dependentName);\n if (existing) {\n existing.count++;\n } else {\n dependentMap.set(dependentName, { location: loc, count: 1 });\n }\n }\n }\n const sortedDependents = [...dependentMap.entries()].sort((a, b) => a[0].localeCompare(b[0]));\n // Calculate max dependent name length for alignment\n const maxDependentNameLen = Math.max(0, ...sortedDependents.map(([name]) => name.length));\n for (const [dependentName, { location, count }] of sortedDependents) {\n const packageJsonPath = path.join(location, 'package.json');\n const relativePath = path.relative(forkPath, packageJsonPath);\n const paddedName = dependentName.padEnd(maxDependentNameLen);\n console.info(\n ` ${pc.dim('•')} ${paddedName} ${hyperlink(relativePath, `file://${packageJsonPath}`)} ${pc.dim(`${count}`)}`,\n );\n }\n}\n\n/**\n * Prompt user to select packages to update, then run pnpm up.\n */\nasync function promptForUpdates(\n packages: EnhancedPackageInfo[],\n forkPath: string,\n auditResult: AuditResult | null,\n): Promise<void> {\n const hasVulnerabilities =\n auditResult !== null && Object.values(auditResult.metadata?.vulnerabilities || {}).some((c) => c > 0);\n const hasPackages = packages.length > 0;\n\n // Ask if user wants to proceed (message adapts to what's available)\n let confirmMessage = 'update packages?';\n if (hasVulnerabilities && hasPackages) {\n confirmMessage = 'update packages and fix vulnerabilities?';\n } else if (hasVulnerabilities) {\n confirmMessage = 'fix vulnerabilities?';\n }\n\n let wantsUpdate: boolean;\n try {\n wantsUpdate = await confirm({\n message: confirmMessage,\n default: true,\n });\n } catch {\n return;\n }\n if (!wantsUpdate) return;\n\n console.info();\n\n // Build choice item for a package\n const makeChoice = (pkg: EnhancedPackageInfo) => {\n const devTag = pkg.isDev ? pc.dim(' (dev)') : '';\n const version = `${pc.red(pkg.current)} → ${pc.green(pkg.latest)}`;\n const pinnedWarning =\n pkg.pinnedIn.length > 0 ? ` ${warningMark} ${pc.dim(`pinned in ${pkg.pinnedIn.join(', ')}`)}` : '';\n return {\n name: `${pkg.name}${devTag} ${version}${pinnedWarning}`,\n value: pkg.name,\n checked: false,\n };\n };\n\n // Sentinel value for the audit --fix checkbox\n const AUDIT_FIX_VALUE = '__audit_fix__';\n\n // Split packages into groups: pinned and regular\n const pinned = packages.filter((p) => p.pinnedIn.length > 0);\n const regular = packages.filter((p) => p.pinnedIn.length === 0);\n\n // Build grouped choices with separators\n const choices: Array<{ name: string; value: string; checked: boolean } | Separator> = [];\n\n // Add audit --fix checkbox at the top when vulnerabilities exist\n if (hasVulnerabilities) {\n const vulnMeta = auditResult?.metadata?.vulnerabilities || {};\n const parts: string[] = [];\n if (vulnMeta.critical) parts.push(pc.red(`${vulnMeta.critical} critical`));\n if (vulnMeta.high) parts.push(pc.red(`${vulnMeta.high} high`));\n if (vulnMeta.moderate) parts.push(pc.yellow(`${vulnMeta.moderate} moderate`));\n if (vulnMeta.low) parts.push(pc.blue(`${vulnMeta.low} low`));\n const vulnSummary = parts.length > 0 ? ` ${pc.dim('·')} ${parts.join(' ')}` : '';\n choices.push(new Separator(pc.red(`── vulnerabilities${vulnSummary} ──`)));\n choices.push({\n name: `${pc.cyan('pnpm audit --fix override')} ${pc.dim('add overrides for non-vulnerable versions')}`,\n value: AUDIT_FIX_VALUE,\n checked: false,\n });\n }\n\n if (pinned.length > 0) {\n choices.push(new Separator(pc.yellow(`── pinned (${pinned.length}) ──`)));\n choices.push(...pinned.map(makeChoice));\n }\n if (regular.length > 0) {\n if (pinned.length > 0 || hasVulnerabilities) {\n choices.push(new Separator(pc.dim(`── packages (${regular.length}) ──`)));\n }\n choices.push(...regular.map(makeChoice));\n }\n\n let selected: string[];\n try {\n selected = await checkbox({\n message: 'toggle packages to update',\n choices,\n required: true,\n pageSize: 20,\n loop: false,\n theme: {\n icon: {\n cursor: '❯ ',\n },\n style: {\n highlight: (text: string) => text,\n keysHelpTip: (keys: [string, string][]) => {\n const tips = keys.map(([key, action]: [string, string]) => `${pc.dim(key)} ${action}`);\n return tips.join(' ');\n },\n renderSelectedChoices: (selectedChoices: Array<{ value?: string }>) =>\n pc.dim(`${selectedChoices.length} package${selectedChoices.length !== 1 ? 's' : ''} selected`),\n },\n },\n });\n } catch {\n // User pressed Ctrl+C or escaped\n return;\n }\n\n // Extract audit --fix selection and filter it from package selections\n const runAuditFix = selected.includes(AUDIT_FIX_VALUE);\n const selectedPackages = selected.filter((s) => s !== AUDIT_FIX_VALUE);\n\n // Print summary of what will happen\n const summaryParts: string[] = [];\n if (selectedPackages.length > 0) {\n summaryParts.push(`updating ${selectedPackages.length} package${selectedPackages.length !== 1 ? 's' : ''}`);\n }\n if (runAuditFix) {\n summaryParts.push('then updating dependencies');\n }\n console.info();\n console.info(pc.green(`✓ ${summaryParts.join(' ')}`));\n console.info();\n\n // Check if any major updates are selected\n const selectedMajor = packages.filter((p) => selectedPackages.includes(p.name) && p.isMajorUpdate);\n if (selectedMajor.length > 0) {\n const majorNames = selectedMajor.map((p) => pc.bold(p.name)).join(', ');\n try {\n const proceed = await confirm({\n message: `${selectedMajor.length} major update${selectedMajor.length > 1 ? 's' : ''} selected (${majorNames}). proceed?`,\n default: true,\n });\n if (!proceed) {\n console.info(pc.dim(' update cancelled'));\n return;\n }\n } catch {\n return;\n }\n }\n\n const catalogPackages = readCatalogPackageNames(forkPath);\n\n // Group selected packages by workspace\n const workspacePackages = new Map<string, { packages: string[] }>();\n for (const pkgName of selectedPackages) {\n const pkg = packages.find((p) => p.name === pkgName);\n if (!pkg) continue;\n\n for (let i = 0; i < pkg.dependents.length; i++) {\n const dependent = pkg.dependents[i];\n if (!workspacePackages.has(dependent)) {\n workspacePackages.set(dependent, { packages: [] });\n }\n workspacePackages.get(dependent)?.packages.push(pkgName);\n }\n }\n\n // Run pnpm audit --fix first (before package updates) so overrides are applied during install\n if (runAuditFix) {\n console.info(pc.dim('running pnpm audit --fix override...'));\n const auditFixResult = spawnSync('pnpm', ['audit', '--fix', 'override'], {\n cwd: forkPath,\n stdio: 'inherit',\n });\n\n console.info();\n if (auditFixResult.status === 0) {\n console.info(pc.green('✓ pnpm audit --fix override completed'));\n } else {\n console.error(pc.red(`✗ pnpm audit --fix override failed (exit code ${auditFixResult.status})`));\n }\n }\n\n // Summarize impacted workspaces before running a single workspace-wide update.\n // The two-phase normalization below guards against catalog version mismatches\n // (ERR_PNPM_CATALOG_VERSION_MISMATCH) that could occur under catalogMode=strict.\n // The workspace now uses catalogMode=manual, so this is defensive only, but it\n // remains harmless and keeps audit robust if strict mode is ever reintroduced.\n for (const [workspace, { packages: pkgs }] of workspacePackages) {\n const pkgList = pkgs.join(', ');\n console.info(`${pc.cyan('↑')} ${pc.bold(workspace)}: ${pc.dim(pkgList)}`);\n }\n\n if (selectedPackages.length > 0) {\n console.info();\n\n const selectedCatalogPackages = selectedPackages.filter((pkgName) => catalogPackages.has(pkgName));\n\n if (selectedCatalogPackages.length > 0) {\n console.info(pc.dim(`normalizing catalog consumers: ${selectedCatalogPackages.join(', ')}`));\n const normalizeResult = spawnSync('pnpm', ['-r', 'up', ...selectedCatalogPackages], {\n cwd: forkPath,\n stdio: 'inherit',\n });\n\n console.info();\n if (normalizeResult.status !== 0) {\n console.error(pc.red(`✗ catalog normalization failed (exit code ${normalizeResult.status})`));\n return;\n }\n }\n\n // Run one recursive update so pnpm can rewrite catalogs and direct consumers atomically.\n const result = spawnSync('pnpm', ['-r', 'up', '--latest', ...selectedPackages], {\n cwd: forkPath,\n stdio: 'inherit',\n });\n\n console.info();\n if (result.status === 0) {\n console.info(pc.green(`✓ ${selectedPackages.length} package${selectedPackages.length > 1 ? 's' : ''} updated`));\n } else {\n console.error(pc.red(`✗ update failed (exit code ${result.status})`));\n }\n }\n}\n\n/**\n * Print vulnerability summary section.\n */\nfunction printVulnerabilityResults(auditResult: AuditResult | null, vulnMap: Map<string, VulnerabilityInfo[]>): void {\n if (auditResult && vulnMap.size > 0) {\n const vulnMeta = auditResult.metadata?.vulnerabilities || {};\n const criticalCount = vulnMeta.critical || 0;\n const highCount = vulnMeta.high || 0;\n const moderateCount = vulnMeta.moderate || 0;\n const lowCount = vulnMeta.low || 0;\n\n console.info();\n console.info(\n `${pc.red('⚠')} ${pc.bold('vulnerabilities')} ${pc.dim('·')} ` +\n (criticalCount > 0 ? pc.red(`${criticalCount} critical `) : '') +\n (highCount > 0 ? pc.red(`${highCount} high `) : '') +\n (moderateCount > 0 ? pc.yellow(`${moderateCount} moderate `) : '') +\n (lowCount > 0 ? pc.blue(`${lowCount} low`) : ''),\n );\n console.info('─'.repeat(60));\n\n // List vulnerable packages with details\n for (const [pkgName, vulns] of vulnMap.entries()) {\n for (const vuln of vulns) {\n const severityIcon = getVulnIcon(vuln.severity);\n const cveStr = vuln.cves.length > 0 ? pc.dim(` ${vuln.cves[0]}`) : '';\n // Build source info: \"in workspace via direct-dep\" or just \"in workspace\"\n let sourceStr = '';\n if (vuln.workspace) {\n sourceStr = pc.dim(` in ${vuln.workspace}`);\n if (vuln.directDependency) {\n sourceStr += pc.dim(` via ${vuln.directDependency}`);\n }\n }\n const title = middleTruncate(vuln.title, 60);\n console.info(\n `${severityIcon} ${pc.white(pkgName)} ${pc.dim(vuln.vulnerableVersions)}${sourceStr} ${pc.dim('·')} ${title}${cveStr}`,\n );\n }\n }\n } else {\n console.info();\n console.info(`${pc.green('✓')} no vulnerabilities found`);\n }\n\n console.info();\n}\n\nfunction readCatalogPackageNames(forkPath: string): Set<string> {\n const workspacePath = path.join(forkPath, 'pnpm-workspace.yaml');\n try {\n const content = fs.readFileSync(workspacePath, 'utf-8');\n return new Set(Object.keys(parseYamlBlockMap(content, 'catalog')));\n } catch {\n return new Set();\n }\n}\n\n/**\n * Reads all pnpm.overrides from package.json and pnpm-workspace.yaml.\n * Returns a map of override key -> { target version, source file }.\n */\nfunction readOverrides(forkPath: string): Map<string, { target: string; source: string }> {\n const overrides = new Map<string, { target: string; source: string }>();\n\n // Read from package.json pnpm.overrides\n const pkgJsonPath = path.join(forkPath, 'package.json');\n try {\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n const pnpmOverrides = pkgJson.pnpm?.overrides || {};\n for (const [key, value] of Object.entries(pnpmOverrides)) {\n overrides.set(key, { target: value as string, source: 'package.json' });\n }\n } catch {\n // skip\n }\n\n // Read from pnpm-workspace.yaml overrides\n const workspacePath = path.join(forkPath, 'pnpm-workspace.yaml');\n try {\n const content = fs.readFileSync(workspacePath, 'utf-8');\n const wsOverrides = parseYamlBlockMap(content, 'overrides');\n for (const [key, value] of Object.entries(wsOverrides)) {\n overrides.set(key, { target: value, source: 'pnpm-workspace.yaml' });\n }\n } catch {\n // skip\n }\n\n return overrides;\n}\n\n/**\n * Checks which pnpm.overrides are still needed by cross-referencing\n * with current audit results and installed versions.\n */\nasync function checkOverrides(forkPath: string): Promise<void> {\n const spinner = createSpinner('checking overrides against current audit...');\n\n const overrides = readOverrides(forkPath);\n\n if (overrides.size === 0) {\n spinnerSuccess('no pnpm.overrides found');\n return;\n }\n\n // Run audit to see current vulnerabilities\n const auditResult = await runPnpmAudit(forkPath);\n\n // Build set of currently vulnerable package names from advisories\n const activeAdvisoryPackages = new Set<string>();\n if (auditResult?.advisories) {\n for (const advisory of Object.values(auditResult.advisories)) {\n activeAdvisoryPackages.add(advisory.module_name);\n }\n }\n\n spinner.stop();\n\n // Categorize each override\n const securityOverrides: Array<{ key: string; pkg: string; target: string; source: string; status: string }> = [];\n const pinOverrides: Array<{ key: string; target: string; source: string }> = [];\n\n for (const [key, { target, source }] of overrides) {\n // Security overrides have version selectors like \"pkg@<=1.0.0\" or \"pkg@>=1.0.0 <2.0.0\"\n const atIndex = key.indexOf('@', key.startsWith('@') ? 1 : 0);\n if (atIndex > 0) {\n const pkg = key.slice(0, atIndex);\n const hasActiveAdvisory = activeAdvisoryPackages.has(pkg);\n const status = hasActiveAdvisory ? 'active' : 'likely stale';\n securityOverrides.push({ key, pkg, target, source, status });\n } else {\n pinOverrides.push({ key, target, source });\n }\n }\n\n // Print results\n const allKeys = Array.from(overrides.keys());\n const allValues = Array.from(overrides.values());\n const maxKeyLen = Math.max(8, ...allKeys.map((k) => k.length));\n const maxTargetLen = Math.max(6, ...allValues.map((v) => v.target.length));\n\n if (securityOverrides.length > 0) {\n console.info(pc.bold(`security overrides (${securityOverrides.length})`));\n console.info('─'.repeat(60));\n\n for (const o of securityOverrides) {\n const icon = o.status === 'active' ? pc.red('●') : pc.green('○');\n const statusText = o.status === 'active' ? pc.red('active') : pc.green('likely stale');\n const keyText = pc.white(o.key.padEnd(maxKeyLen));\n const targetText = pc.dim(o.target.padEnd(maxTargetLen));\n const sourceText = pc.dim(o.source);\n console.info(` ${icon} ${keyText} → ${targetText} ${statusText} ${sourceText}`);\n }\n console.info();\n }\n\n if (pinOverrides.length > 0) {\n console.info(pc.bold(`version pins (${pinOverrides.length})`));\n console.info('─'.repeat(60));\n\n for (const o of pinOverrides) {\n const keyText = pc.white(o.key.padEnd(maxKeyLen));\n const targetText = pc.dim(o.target.padEnd(maxTargetLen));\n const sourceText = pc.dim(o.source);\n console.info(` ${pc.blue('◆')} ${keyText} → ${targetText} ${sourceText}`);\n }\n console.info();\n }\n\n // Summary\n const staleCount = securityOverrides.filter((o) => o.status === 'likely stale').length;\n const activeCount = securityOverrides.filter((o) => o.status === 'active').length;\n\n if (staleCount > 0) {\n console.info(\n `${pc.green('○')} ${staleCount} override${staleCount !== 1 ? 's' : ''} likely stale — no matching advisory found in current audit`,\n );\n console.info(pc.dim(' overrides mask vulnerabilities — verify by temporarily removing and running pnpm audit'));\n }\n if (activeCount > 0) {\n console.info(\n `${pc.red('●')} ${activeCount} override${activeCount !== 1 ? 's' : ''} still active — advisory present without override`,\n );\n }\n if (pinOverrides.length > 0) {\n console.info(\n `${pc.blue('◆')} ${pinOverrides.length} version pin${pinOverrides.length !== 1 ? 's' : ''} — not security-related, review manually`,\n );\n }\n console.info();\n}\n","/**\n * Audit utilities for the Cella CLI audit service.\n *\n * Provides npm registry fetching, changelog detection, vulnerability parsing, and caching.\n */\n\nimport { execFile } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { promisify } from 'node:util';\nimport pc from './colors';\n\nconst execFileAsync = promisify(execFile);\n\n/*************************************************************************************************\n * Types\n ************************************************************************************************/\n\ninterface OutdatedPackage {\n current: string;\n latest: string;\n wanted: string;\n isDeprecated: boolean;\n dependencyType: 'dependencies' | 'devDependencies';\n dependentPackages: Array<{ name: string; location: string }>;\n}\n\nexport interface NpmRegistryData {\n repository?: { type: string; url: string; directory?: string };\n homepage?: string;\n bugs?: { url: string };\n}\n\ninterface CachedPackageData {\n repoUrl: string | null;\n changelogUrl: string | null;\n fetchedAt: number;\n}\n\ninterface ChangelogCache {\n [packageName: string]: CachedPackageData;\n}\n\nexport interface EnhancedPackageInfo {\n name: string;\n current: string;\n latest: string;\n dependents: string[];\n dependentLocations: string[];\n isDev: boolean;\n isMajorUpdate: boolean;\n /** Workspace names where this package is pinned to an exact version (no ^ or ~) */\n pinnedIn: string[];\n repoUrl: string | null;\n changelogUrl: string | null;\n releasesUrl: string | null;\n vulnerabilities: VulnerabilityInfo[];\n}\n\n/** Vulnerability severity levels */\nexport type VulnerabilitySeverity = 'critical' | 'high' | 'moderate' | 'low' | 'info';\n\n/** Vulnerability info for a package */\nexport interface VulnerabilityInfo {\n id: number;\n title: string;\n severity: VulnerabilitySeverity;\n url: string;\n vulnerableVersions: string;\n patchedVersions: string;\n cves: string[];\n /** The workspace/dependent containing this vulnerability (e.g., 'frontend', 'backend') */\n workspace: string | null;\n /** The direct dependency in the workspace that brought in this vulnerable package */\n directDependency: string | null;\n}\n\n/** Audit result from pnpm audit --json */\nexport interface AuditResult {\n advisories: Record<string, AuditAdvisory>;\n metadata: {\n vulnerabilities: Record<VulnerabilitySeverity, number>;\n dependencies: number;\n devDependencies: number;\n };\n}\n\nexport interface AuditAdvisory {\n id: number;\n title: string;\n module_name: string;\n severity: VulnerabilitySeverity;\n vulnerable_versions: string;\n patched_versions: string;\n cves: string[];\n url: string;\n findings: Array<{ version: string; paths: string[] }>;\n}\n\n/** Parsed dependency path info from pnpm audit */\ninterface DependencyPathInfo {\n /** The workspace name (e.g., 'frontend', 'backend') */\n workspace: string | null;\n /** The direct dependency in the workspace that starts the chain */\n directDependency: string | null;\n}\n\n/*************************************************************************************************\n * Constants\n ************************************************************************************************/\n\n/** Cache file location (in cli/cella directory) */\nexport const CACHE_FILE = path.join(import.meta.dirname, '..', '..', '.audit.cache.json');\n\n/** Cache TTL: 7 days in ms */\nconst CACHE_TTL = 7 * 24 * 60 * 60 * 1000;\n\n/** Common changelog file paths to check in GitHub repos */\nexport const CHANGELOG_PATHS = ['CHANGELOG.md', 'CHANGELOG', 'changelog.md', 'HISTORY.md', 'CHANGES.md', 'NEWS.md'];\n\n/** Default branches to check for changelog files */\nexport const DEFAULT_BRANCHES = ['main', 'master'] as const;\n\n/*************************************************************************************************\n * Cache Functions\n ************************************************************************************************/\n\n/** Loads the changelog cache from disk. */\nexport function loadCache(): ChangelogCache {\n try {\n if (fs.existsSync(CACHE_FILE)) {\n return JSON.parse(fs.readFileSync(CACHE_FILE, 'utf-8'));\n }\n } catch {\n // Ignore cache read errors\n }\n return {};\n}\n\n/** Saves the changelog cache to disk. */\nexport function saveCache(cache: ChangelogCache): void {\n try {\n fs.writeFileSync(CACHE_FILE, `${JSON.stringify(cache, null, 2)}\\n`);\n } catch {\n // Ignore cache write errors\n }\n}\n\n/** Clears the changelog cache. */\nexport function clearCache(): void {\n try {\n if (fs.existsSync(CACHE_FILE)) {\n fs.unlinkSync(CACHE_FILE);\n console.info(pc.green('✓ cache cleared successfully'));\n } else {\n console.info(pc.yellow('no cache file found'));\n }\n } catch (err) {\n console.error(pc.red('failed to clear cache:'), err);\n }\n}\n\n/*************************************************************************************************\n * NPM Registry Functions\n ************************************************************************************************/\n\n/** Fetches package metadata from npm registry. */\nexport async function fetchNpmMetadata(packageName: string): Promise<NpmRegistryData | null> {\n try {\n const response = await fetch(`https://registry.npmjs.org/${packageName}`);\n if (!response.ok) return null;\n return (await response.json()) as NpmRegistryData;\n } catch {\n return null;\n }\n}\n\n/**\n * Extracts GitHub repo URL from npm registry data.\n * Normalizes git+https:// URLs to https:// format.\n */\nexport function getRepoUrl(data: NpmRegistryData | null): string | null {\n if (!data?.repository?.url) return null;\n\n let url = data.repository.url;\n\n // Normalize git+https:// to https://\n if (url.startsWith('git+')) {\n url = url.slice(4);\n }\n\n // Remove .git suffix\n if (url.endsWith('.git')) {\n url = url.slice(0, -4);\n }\n\n // Convert git:// to https://\n if (url.startsWith('git://')) {\n url = url.replace('git://', 'https://');\n }\n\n return url;\n}\n\n/** Checks whether the provided URL points to a GitHub repository. */\nfunction isGitHubRepoUrl(repoUrl: string | null): repoUrl is string {\n if (!repoUrl) return false;\n try {\n const parsed = new URL(repoUrl);\n return parsed.hostname === 'github.com' || parsed.hostname === 'www.github.com';\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if a file exists in a GitHub repo and returns the branch name if found.\n * Returns null if file doesn't exist on any branch.\n */\nasync function findGitHubFile(repoUrl: string, filePath: string): Promise<string | null> {\n if (!isGitHubRepoUrl(repoUrl)) return null;\n\n for (const branch of DEFAULT_BRANCHES) {\n const rawUrl = repoUrl.replace('github.com', 'raw.githubusercontent.com').concat(`/${branch}/${filePath}`);\n\n try {\n const response = await fetch(rawUrl, { method: 'HEAD' });\n if (response.ok) return branch;\n } catch {\n // Continue to next branch\n }\n }\n return null;\n}\n\n/**\n * Finds the changelog URL for a package by checking common locations.\n * Results are cached to avoid repeated GitHub requests.\n */\nexport async function findChangelogUrl(\n repoUrl: string | null,\n packageName: string,\n cache: ChangelogCache,\n): Promise<string | null> {\n if (!isGitHubRepoUrl(repoUrl)) return null;\n\n // Check cache first\n const cached = cache[packageName];\n if (cached && Date.now() - cached.fetchedAt < CACHE_TTL) {\n return cached.changelogUrl;\n }\n\n // Try each common changelog path - findGitHubFile returns branch if found\n for (const changelogPath of CHANGELOG_PATHS) {\n const branch = await findGitHubFile(repoUrl, changelogPath);\n if (branch) {\n const blobUrl = `${repoUrl}/blob/${branch}/${changelogPath}`;\n // Cache the result\n cache[packageName] = {\n repoUrl,\n changelogUrl: blobUrl,\n fetchedAt: Date.now(),\n };\n return blobUrl;\n }\n }\n\n // No changelog found, cache negative result\n cache[packageName] = {\n repoUrl,\n changelogUrl: null,\n fetchedAt: Date.now(),\n };\n\n return null;\n}\n\n/** Get GitHub releases URL */\nexport function getReleasesUrl(repoUrl: string | null): string | null {\n if (!isGitHubRepoUrl(repoUrl)) return null;\n return `${repoUrl}/releases`;\n}\n\n/*************************************************************************************************\n * Version Utilities\n ************************************************************************************************/\n\n/** Checks if the update is a major version change. */\nexport function isMajorVersionChange(current: string, latest: string): boolean {\n const currentMajor = current.split('.')[0]?.replace(/^\\D+/, '');\n const latestMajor = latest.split('.')[0]?.replace(/^\\D+/, '');\n if (!currentMajor || !latestMajor) return false;\n return Number.parseInt(latestMajor, 10) > Number.parseInt(currentMajor, 10);\n}\n\n/*************************************************************************************************\n * Outdated Package Functions\n ************************************************************************************************/\n\n/**\n * Runs pnpm outdated and returns JSON output.\n * Note: pnpm outdated exits with code 1 when packages are outdated,\n * so we need to handle this as a normal case, not an error.\n */\nexport async function getOutdatedPackages(cwd: string): Promise<Record<string, OutdatedPackage>> {\n try {\n const { stdout } = await execFileAsync('pnpm', ['-r', 'outdated', '--json'], {\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024, // 10MB buffer for large outputs\n cwd,\n });\n\n if (!stdout || stdout.trim() === '') {\n return {};\n }\n\n return JSON.parse(stdout);\n } catch (error) {\n // pnpm outdated exits with code 1 when there are outdated packages\n // This is expected behavior, not an error\n if (error instanceof Error && 'stdout' in error) {\n const stdout = (error as { stdout: string }).stdout;\n if (stdout?.trim()) {\n try {\n return JSON.parse(stdout);\n } catch {\n // JSON parse failed, return empty\n return {};\n }\n }\n }\n return {};\n }\n}\n\n/*************************************************************************************************\n * Vulnerability Functions\n ************************************************************************************************/\n\n/**\n * Runs pnpm audit and returns parsed JSON output.\n * Returns null if audit fails or no vulnerabilities found.\n */\nexport async function runPnpmAudit(cwd: string): Promise<AuditResult | null> {\n try {\n const { stdout } = await execFileAsync('pnpm', ['audit', '--json'], {\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024,\n cwd,\n });\n\n if (!stdout || stdout.trim() === '') {\n return null;\n }\n\n return JSON.parse(stdout) as AuditResult;\n } catch (error) {\n // pnpm audit exits with non-zero when vulnerabilities found\n if (error instanceof Error && 'stdout' in error) {\n const stdout = (error as { stdout: string }).stdout;\n if (stdout?.trim()) {\n try {\n return JSON.parse(stdout) as AuditResult;\n } catch {\n return null;\n }\n }\n }\n return null;\n }\n}\n\n/**\n * Parses vulnerability paths to extract workspace and direct dependency.\n * Path format is like \"workspace>direct-dep>transitive>vulnerable-pkg\".\n * Examples:\n * - \"frontend>virtua>solid-js>seroval\" -> { workspace: 'frontend', directDependency: 'virtua' }\n * - \"backend>jsx-email>esbuild\" -> { workspace: 'backend', directDependency: 'jsx-email' }\n * - \"esbuild\" (direct) -> { workspace: null, directDependency: null }\n */\nfunction parseDependencyPath(paths: string[]): DependencyPathInfo {\n for (const pathStr of paths) {\n const parts = pathStr.split('>');\n if (parts.length >= 2) {\n // First part is workspace, second is the direct dependency in that workspace\n return {\n workspace: parts[0],\n directDependency: parts.length > 2 ? parts[1] : null,\n };\n }\n }\n return { workspace: null, directDependency: null };\n}\n\n/** Creates a map of package name -> vulnerabilities from audit result. */\nexport function buildVulnerabilityMap(auditResult: AuditResult | null): Map<string, VulnerabilityInfo[]> {\n const map = new Map<string, VulnerabilityInfo[]>();\n if (!auditResult?.advisories) return map;\n\n for (const advisory of Object.values(auditResult.advisories)) {\n // Extract workspace and direct dependency from findings paths\n const allPaths = advisory.findings?.flatMap((f) => f.paths) || [];\n const { workspace, directDependency } = parseDependencyPath(allPaths);\n\n const existing = map.get(advisory.module_name) || [];\n existing.push({\n id: advisory.id,\n title: advisory.title,\n severity: advisory.severity,\n url: advisory.url,\n vulnerableVersions: advisory.vulnerable_versions,\n patchedVersions: advisory.patched_versions,\n cves: advisory.cves || [],\n workspace,\n directDependency,\n });\n map.set(advisory.module_name, existing);\n }\n\n return map;\n}\n\n/*************************************************************************************************\n * Display Utilities\n ************************************************************************************************/\n\n/** Gets vulnerability severity icon with color. */\nexport function getVulnIcon(severity: VulnerabilitySeverity): string {\n switch (severity) {\n case 'critical':\n return pc.red('●');\n case 'high':\n return pc.red('●');\n case 'moderate':\n return pc.yellow('●');\n case 'low':\n return pc.blue('●');\n default:\n return pc.gray('●');\n }\n}\n\n/** Gets the highest severity from a list of vulnerabilities. */\nexport function getHighestSeverity(vulns: VulnerabilityInfo[]): VulnerabilitySeverity | null {\n if (vulns.length === 0) return null;\n const order: VulnerabilitySeverity[] = ['critical', 'high', 'moderate', 'low', 'info'];\n for (const severity of order) {\n if (vulns.some((v) => v.severity === severity)) return severity;\n }\n return null;\n}\n\n/**\n * Truncates a string in the middle if it exceeds maxLen.\n * Example: \"very-long-package-name\" -> \"very-lo…e-name\"\n */\nexport function middleTruncate(str: string, maxLen: number): string {\n if (str.length <= maxLen) return str;\n const ellipsis = '…';\n const charsToShow = maxLen - ellipsis.length;\n const frontChars = Math.ceil(charsToShow / 2);\n const backChars = Math.floor(charsToShow / 2);\n return str.slice(0, frontChars) + ellipsis + str.slice(-backChars);\n}\n\n/** Formats dependents as \"first +N\" if multiple. */\nexport function formatDependents(dependents: string[]): string {\n if (dependents.length === 0) return '';\n if (dependents.length === 1) return dependents[0];\n return `${dependents[0]} +${dependents.length - 1}`;\n}\n","/**\n * Extract the indented lines of a top-level YAML block (e.g. `overrides:`).\n * Stops at the next non-indented, non-empty line. Comment lines are skipped.\n */\nfunction yamlBlockLines(content: string, key: string): string[] {\n const lines: string[] = [];\n let inBlock = false;\n\n for (const line of content.split('\\n')) {\n if (new RegExp(`^${key}:\\\\s*$`).test(line)) {\n inBlock = true;\n continue;\n }\n if (!inBlock) continue;\n\n const trimmed = line.trim();\n if (trimmed.startsWith('#')) continue;\n // End of block: non-indented non-empty line (next top-level key)\n if (trimmed !== '' && !line.startsWith(' ') && !line.startsWith('\\t')) break;\n lines.push(line);\n }\n\n return lines;\n}\n\n/**\n * Parse a top-level YAML block of flat `key: value` entries into a record.\n * Quotes around keys and values are stripped.\n */\nexport function parseYamlBlockMap(content: string, key: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of yamlBlockLines(content, key)) {\n const match = line.match(/^\\s+(.+?):\\s+['\"]?([^'\"]+)['\"]?\\s*$/);\n if (match) {\n result[match[1].replace(/^['\"]|['\"]$/g, '')] = match[2];\n }\n }\n return result;\n}\n\n/**\n * Parse a top-level YAML block of `- item` list entries into an array.\n */\nexport function parseYamlBlockList(content: string, key: string): string[] {\n const items: string[] = [];\n for (const line of yamlBlockLines(content, key)) {\n const trimmed = line.trim();\n if (trimmed.startsWith('- ')) items.push(trimmed.slice(2).trim());\n }\n return items;\n}\n","/**\n * Contributions service for sync CLI.\n *\n * Upstream-side (cella): based on the configured `forks`, lets the user pick a\n * single fork, pulls its `pullBranch` and builds a clean local `contrib/<fork>`\n * branch with only that fork's contributed files. Then shows an interactive TUI\n * to review and adopt individual files into the working tree.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport {\n createPrompt,\n isDownKey,\n isEnterKey,\n isSpaceKey,\n isUpKey,\n useKeypress,\n useMemo,\n usePagination,\n useState,\n} from '@inquirer/core';\nimport { select } from '@inquirer/prompts';\nimport type { FileStatus, RuntimeConfig } from '../config/types';\nimport pc from '../utils/colors';\nimport { DEFAULT_BRANCH, loadConfig } from '../utils/config';\nimport { gitDiffFile, openDiffInBrowser } from '../utils/diff';\nimport { createSpinner, DIVIDER, spinnerFail, spinnerSuccess, warningMark, writeStdout } from '../utils/display';\nimport { getCurrentBranch, git, removeFileFromWorktree, restoreWorktreeFromRef } from '../utils/git';\nimport { buildContribBranch, countDetection, detectContributableFiles } from './contrib-core';\nimport { printNoForksHint, type ValidatedFork, validateForkPath } from './fork-utils';\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\ninterface ContribItem {\n /** File path relative to repo root */\n path: string;\n /** Local contrib branch ref (e.g., contrib/myfork) */\n ref: string;\n /** True if adopting this means deleting the file in cella */\n deleted: boolean;\n /** True if the file does not exist in cella yet (adopting it creates a new file) */\n created?: boolean;\n /** Analyzer status from cella's POV (behind = fork ahead, diverged = both changed) */\n status?: FileStatus;\n /** Relative date of the fork's change (e.g. '3 days ago') */\n changedAt?: string;\n /** Unix epoch seconds of the fork's change, for sorting */\n changedTs?: number;\n /** Lines added in the fork vs cella base (null for binary files) */\n additions?: number | null;\n /** Lines removed in the fork vs cella base (null for binary files) */\n deletions?: number | null;\n /** Whether file is selected for acceptance */\n checked: boolean;\n}\n\ninterface ContribPromptConfig {\n message: string;\n items: ContribItem[];\n /** Name of the fork being reviewed (used to label diffs cella/ vs <fork>/) */\n forkName: string;\n /** Base ref the contrib branches were built on (for diffing) */\n baseRef: string;\n /** Repo path where contrib branches live */\n cwd: string;\n pageSize?: number;\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\n/**\n * Open a browser diff for a contrib file (cella base vs the fork's version).\n * Returns the written page path, or null when the file has no changes.\n */\nasync function showContribDiff(\n item: ContribItem,\n baseRef: string,\n cwd: string,\n forkName: string,\n): Promise<string | null> {\n const patch = gitDiffFile(cwd, `${baseRef}..${item.ref}`, item.path);\n if (patch.length === 0) return null;\n return openDiffInBrowser(patch.toString(), { filePath: item.path, srcLabel: 'cella', dstLabel: forkName }, cwd);\n}\n\nfunction shouldApplyContributionsUnstaged(repoPath: string): boolean {\n return JSON.parse(readFileSync(join(repoPath, 'package.json'), 'utf8')).name === 'cella';\n}\n\n// ── Custom prompt ────────────────────────────────────────────────────────────\n\n/**\n * Interactive prompt for reviewing contributed files.\n * Returns items selected for acceptance.\n */\nconst contribPrompt = createPrompt<ContribItem[], ContribPromptConfig>((config, done) => {\n const { pageSize = 20, baseRef, cwd, forkName } = config;\n\n const [items, setItems] = useState<ContribItem[]>(config.items);\n const [active, setActive] = useState(0);\n const [statusMsg, setStatusMsg] = useState('');\n const [promptStatus, setPromptStatus] = useState<'idle' | 'done'>('idle');\n\n const bounds = useMemo(() => {\n if (items.length === 0) return { first: 0, last: 0 };\n return { first: 0, last: items.length - 1 };\n }, [items]);\n\n useKeypress(async (key) => {\n if (items.length === 0) {\n if (isEnterKey(key) || key.name === 'q') {\n setPromptStatus('done');\n done([]);\n }\n return;\n }\n\n // q = quit\n if (key.name === 'q') {\n setPromptStatus('done');\n done([]);\n return;\n }\n\n // Enter = accept selected\n if (isEnterKey(key)) {\n const selected = items.filter((i) => i.checked);\n if (selected.length === 0) {\n setStatusMsg('select files with space first, or q to quit');\n return;\n }\n setPromptStatus('done');\n done(selected);\n return;\n }\n\n // Navigation\n if (key.ctrl && isUpKey(key)) {\n setActive(bounds.first);\n setStatusMsg('');\n return;\n }\n if (key.ctrl && isDownKey(key)) {\n setActive(bounds.last);\n setStatusMsg('');\n return;\n }\n if (isUpKey(key)) {\n setActive(active <= bounds.first ? bounds.first : active - 1);\n setStatusMsg('');\n return;\n }\n if (isDownKey(key)) {\n setActive(active >= bounds.last ? bounds.last : active + 1);\n setStatusMsg('');\n return;\n }\n\n // Space = toggle selection\n if (isSpaceKey(key)) {\n setItems(items.map((item, i) => (i === active ? { ...item, checked: !item.checked } : item)));\n return;\n }\n\n // d = open diff in browser (non-blocking, the list stays up)\n if (key.name === 'd') {\n try {\n const pagePath = await showContribDiff(items[active], baseRef, cwd, forkName);\n setStatusMsg(pagePath ? `opened ${items[active].path} in browser` : `no changes for ${items[active].path}`);\n } catch (error) {\n setStatusMsg(`diff failed: ${error instanceof Error ? error.message : 'unknown error'}`);\n }\n return;\n }\n\n // a = toggle all (select all, or deselect all if already all selected)\n if (key.name === 'a') {\n const allChecked = items.every((item) => item.checked);\n setItems(items.map((item) => ({ ...item, checked: !allChecked })));\n setStatusMsg(allChecked ? 'deselected all' : 'selected all');\n return;\n }\n });\n\n // Render: done state\n if (promptStatus === 'done') {\n const checked = items.filter((i) => i.checked);\n if (checked.length > 0) {\n return `${pc.green('✓')} ${checked.length} files accepted`;\n }\n return `${pc.green('✓')} done`;\n }\n\n // Render: empty\n if (items.length === 0) {\n return `${pc.green('✓')} no contributions — press enter`;\n }\n\n // Render: paginated list\n const checkedCount = items.filter((i) => i.checked).length;\n\n const page = usePagination({\n items,\n active,\n renderItem({ item, isActive }) {\n const checkbox = item.checked ? pc.green('●') : pc.dim('○');\n const cursor = isActive ? pc.cyan('❯') : ' ';\n const newLabel = item.created ? pc.yellow(' · not in cella') : '';\n const delLabel = item.deleted ? pc.yellow(' [del]') : '';\n const statusTag = item.status === 'diverged' ? pc.yellow(' ⚠ diverged') : '';\n const dateLabel = item.changedAt ? pc.dim(` · ${item.changedAt}`) : '';\n const line = `${cursor} ${checkbox} ${item.path}${delLabel}${statusTag}${newLabel}${dateLabel}`;\n return isActive ? pc.cyan(line) : line;\n },\n pageSize,\n loop: false,\n });\n\n const countInfo =\n checkedCount > 0 ? `${items.length} files, ${pc.green(`${checkedCount} selected`)}` : `${items.length} files`;\n const header = `${pc.cyan('⬇')} ${config.message} ${pc.dim(`(${countInfo})`)}`;\n\n const keys: [string, string][] = [\n ['↑↓', 'navigate'],\n ['d', 'diff in browser'],\n ['a', '(de)select all'],\n ['space', 'select'],\n ['⏎', 'accept'],\n ['q', 'quit'],\n ];\n const helpLine = keys.map(([k, a]) => `${pc.bold(k)} ${pc.dim(a)}`).join(pc.dim(' · '));\n\n const statusLine = statusMsg ? ` ${pc.dim(statusMsg)}` : '';\n\n const lines = [header, page, statusLine, helpLine].filter(Boolean).join('\\n').trimEnd();\n return `${lines}\\x1B[?25l`;\n});\n\n// ── Fork pulling ─────────────────────────────────────────────────────────────\n\n/**\n * Fetch a fork's pullBranch into cella's object store and return the commit sha.\n */\nasync function fetchForkBranch(cellaPath: string, fetchSource: string, pullBranch: string): Promise<string> {\n await git(['fetch', fetchSource, pullBranch], cellaPath);\n return git(['rev-parse', 'FETCH_HEAD'], cellaPath);\n}\n\n/** Short sha + relative date of the fork's committed pullBranch HEAD (for the comparison banner). */\nasync function forkRefMeta(cellaPath: string, forkRef: string): Promise<{ sha: string; date: string }> {\n const out = await git(['log', '-1', '--format=%h%x09%cr', forkRef], cellaPath, { ignoreErrors: true });\n const [sha = forkRef.slice(0, 7), date = 'unknown'] = out.split('\\t');\n return { sha, date };\n}\n\n/**\n * Lines added/removed per file between cella base and the contrib branch.\n * Binary files report null. Used to enrich `--json` output for triage.\n */\nasync function diffStat(\n cellaPath: string,\n baseRef: string,\n ref: string,\n): Promise<Map<string, { additions: number | null; deletions: number | null }>> {\n const out = await git(['diff', '--numstat', `${baseRef}..${ref}`], cellaPath, { ignoreErrors: true });\n const stat = new Map<string, { additions: number | null; deletions: number | null }>();\n for (const line of out.split('\\n')) {\n if (!line.trim()) continue;\n const [a, d, ...rest] = line.split('\\t');\n const path = rest.join('\\t');\n if (!path) continue;\n stat.set(path, {\n additions: a === '-' ? null : Number(a),\n deletions: d === '-' ? null : Number(d),\n });\n }\n return stat;\n}\n\n// ── Main entry ───────────────────────────────────────────────────────────────\n\n/**\n * Run the contributions service.\n *\n * Based on the configured `forks`, lets the user select one or more forks,\n * pulls each fork's `pullBranch`, builds clean local `contrib/<fork>` branches,\n * then presents an interactive TUI to review and adopt individual files.\n */\nexport async function runContributions(config: RuntimeConfig): Promise<void> {\n const forks = config.forks ?? [];\n\n if (forks.length === 0) {\n printNoForksHint('add forks to pull contributions from:');\n return;\n }\n\n // Compare forks against cella's currently checked-out branch, not a fixed\n // configured branch, so contributions reflect the branch you're working on.\n const baseRef = await getCurrentBranch(config.forkPath);\n\n // Warn when not on cella's base branch. The comparison is a 3-way analysis against\n // merge-base(baseRef, fork), so a long-lived feature branch has an older merge-base\n // than 'main' and may surface extra 'diverged' files that would show clean from main.\n if (baseRef !== DEFAULT_BRANCH) {\n console.info(\n `${warningMark} ${pc.yellow(`not on base branch '${DEFAULT_BRANCH}'`)} ${pc.dim(`comparing forks against '${baseRef}'`)}`,\n );\n console.info(\n ` ${pc.dim(`older merge-base may show extra 'diverged' files; switch to '${DEFAULT_BRANCH}' for the cleanest result`)}`,\n );\n console.info('');\n }\n\n const validated = forks.map((fork) => validateForkPath(fork, config.forkPath));\n const validForks = validated.filter((v) => v.valid);\n\n // Select a single fork to pull from\n let selectedFork: ValidatedFork | undefined;\n if (config.fork) {\n const match = validated.find((v) => v.fork.name === config.fork);\n if (!match?.valid) {\n console.error(pc.red(`fork '${config.fork}' not found or invalid in config`));\n return;\n }\n selectedFork = match;\n } else if (config.list || config.json || config.diff) {\n // Non-interactive: require an explicit --fork when multiple forks are configured\n if (validForks.length === 0) {\n console.error(pc.red('no valid forks configured'));\n return;\n }\n if (validForks.length > 1) {\n console.error(pc.red('multiple forks configured; pass --fork <name> to choose one'));\n return;\n }\n selectedFork = validForks[0];\n } else {\n const choices = validated.map((v) => ({\n value: v.fork.name,\n name: v.valid\n ? `${v.fork.name} ${pc.dim(`[${v.fork.pullBranch}] ${v.fork.localPath}`)}`\n : `${v.fork.name} ${pc.dim(v.fork.localPath)}`,\n disabled: v.valid ? false : (v.error ?? 'invalid'),\n }));\n const picked = await select<string>({\n message: 'select fork to pull contributions from:',\n choices,\n loop: false,\n });\n selectedFork = validated.find((v) => v.fork.name === picked);\n }\n\n if (!selectedFork) {\n console.info(pc.dim('no fork selected.'));\n return;\n }\n\n const { fork, resolvedPath } = selectedFork;\n const forkName = fork.name;\n\n // Pull the fork and build a clean contrib/<fork> branch\n createSpinner('pulling fork contributions...');\n const allItems: ContribItem[] = [];\n let forkBanner: { pullBranch: string; sha: string; date: string } | null = null;\n\n try {\n // Prefer the fork's remote (authoritative committed ref) over the local clone.\n const fetchSource = fork.remoteUrl ?? resolvedPath;\n const forkRef = await fetchForkBranch(config.forkPath, fetchSource, fork.pullBranch);\n const meta = await forkRefMeta(config.forkPath, forkRef);\n forkBanner = { pullBranch: fork.pullBranch, sha: meta.sha, date: meta.date };\n\n // Read the fork's own owned folders so its fork-specific modules aren't offered back\n let forkTerritory: string[] = [];\n try {\n const forkConfig = await loadConfig(resolvedPath);\n forkTerritory = forkConfig.overrides?.ignored ?? [];\n } catch {\n // Fork may not have a cella.config.ts — no extra territory to exclude\n }\n\n const detection = await detectContributableFiles(config.forkPath, baseRef, forkRef, config, forkTerritory);\n if (countDetection(detection) > 0) {\n const { branch, appliedFiles } = await buildContribBranch(config.forkPath, baseRef, forkRef, detection, forkName);\n if (appliedFiles.length > 0) {\n const stat = await diffStat(config.forkPath, baseRef, branch);\n const metaByPath = new Map(detection.files.map((f) => [f.path, f]));\n for (const path of [...detection.modified, ...detection.created]) {\n const fileMeta = metaByPath.get(path);\n allItems.push({\n path,\n ref: branch,\n deleted: false,\n created: fileMeta?.kind === 'created',\n status: fileMeta?.status,\n changedAt: fileMeta?.changedAt,\n changedTs: fileMeta?.changedTs,\n additions: stat.get(path)?.additions ?? null,\n deletions: stat.get(path)?.deletions ?? null,\n checked: false,\n });\n }\n for (const path of detection.deleted) {\n const fileMeta = metaByPath.get(path);\n allItems.push({\n path,\n ref: branch,\n deleted: true,\n status: fileMeta?.status,\n changedAt: fileMeta?.changedAt,\n changedTs: fileMeta?.changedTs,\n additions: stat.get(path)?.additions ?? null,\n deletions: stat.get(path)?.deletions ?? null,\n checked: false,\n });\n }\n }\n }\n } catch (error) {\n spinnerFail(`failed to pull ${forkName}`);\n console.info(pc.red(` ✗ ${error instanceof Error ? error.message : 'unknown error'}`));\n return;\n }\n\n if (allItems.length === 0) {\n spinnerSuccess('no contributions found');\n return;\n }\n\n // Sort by most recent fork change first (undated files last), path as tie-breaker,\n // so the top of the list shows where the fork last drifted (further) apart.\n allItems.sort((a, b) => (b.changedTs ?? 0) - (a.changedTs ?? 0) || a.path.localeCompare(b.path));\n\n spinnerSuccess(`${allItems.length} files from ${forkName}`);\n\n // Make the comparison basis explicit: the fork is compared at its committed pullBranch HEAD,\n // not its working tree, so uncommitted fork edits never appear here. Skipped for --list/--diff\n // so their stdout stays clean for machine parsing.\n if (!config.list && !config.diff && forkBanner) {\n console.info(\n ` ${pc.dim(`${forkName}: comparing committed '${forkBanner.pullBranch}' @ ${forkBanner.sha} (${forkBanner.date}) — uncommitted fork changes are not included`)}`,\n );\n }\n\n // Print the unified diff for a single file, then exit (tooling/agent usage).\n if (config.diff) {\n const matches = allItems.filter((i) => i.path === config.diff);\n if (matches.length === 0) {\n console.error(pc.red(`no contribution found for path: ${config.diff}`));\n process.exitCode = 1;\n return;\n }\n for (const item of matches) {\n const diff = gitDiffFile(config.forkPath, `${baseRef}..${item.ref}`, item.path, { dstPrefix: forkName });\n writeStdout(diff.toString());\n }\n return;\n }\n\n // Machine-readable JSON output for tooling/agent usage\n if (config.json) {\n const out = allItems.map((item) => ({\n fork: forkName,\n path: item.path,\n status: item.status ?? null,\n kind: item.deleted ? 'deleted' : 'modified',\n changedAt: item.changedAt ?? null,\n changedTs: item.changedTs ?? null,\n additions: item.additions ?? null,\n deletions: item.deletions ?? null,\n }));\n writeStdout(JSON.stringify(out, null, 2));\n return;\n }\n\n // Non-interactive mode: output enriched list for LLM/agent usage.\n // Columns are tab-separated: fork, status, kind, changedAt, path.\n // Note: status reflects the fork's committed pullBranch HEAD vs cella's base\n // (behind = fork ahead, diverged = both changed), not the fork's working tree.\n if (config.list) {\n for (const item of allItems) {\n const status = item.status ?? 'behind';\n const kind = item.deleted ? 'deleted' : 'modified';\n const changedAt = item.changedAt ?? '-';\n console.info(`${forkName}\\t${status}\\t${kind}\\t${changedAt}\\t${item.path}`);\n }\n return;\n }\n\n console.info();\n console.info(DIVIDER);\n\n // Run interactive prompt\n const selected = await contribPrompt({\n message: `contributions from ${forkName}`,\n items: allItems,\n forkName,\n baseRef,\n cwd: config.forkPath,\n pageSize: 20,\n });\n\n if (selected.length === 0) {\n console.info();\n return;\n }\n\n // Apply selected files into the working tree\n createSpinner(`applying ${selected.length} files...`);\n const applyUnstaged = shouldApplyContributionsUnstaged(config.forkPath);\n\n let applied = 0;\n const errors: string[] = [];\n\n for (const item of selected) {\n try {\n // Reject paths with traversal components (CWE-22)\n if (item.path.includes('..') || item.path.startsWith('/')) {\n errors.push(`${item.path}: rejected (path traversal)`);\n continue;\n }\n if (item.deleted) {\n if (applyUnstaged) {\n await removeFileFromWorktree(config.forkPath, item.path);\n } else {\n await git(['rm', '-f', '--', item.path], config.forkPath, { ignoreErrors: true });\n }\n } else {\n if (applyUnstaged) {\n await restoreWorktreeFromRef(config.forkPath, item.ref, item.path);\n } else {\n await git(['checkout', item.ref, '--', item.path], config.forkPath);\n }\n }\n applied++;\n } catch (error) {\n errors.push(`${item.path}: ${error instanceof Error ? error.message : 'unknown error'}`);\n }\n }\n\n if (errors.length > 0) {\n spinnerFail(`applied ${applied}/${selected.length} files (${errors.length} errors)`);\n for (const err of errors) {\n console.info(pc.red(` ✗ ${err}`));\n }\n } else {\n spinnerSuccess(`applied ${applied} files ${pc.dim(applyUnstaged ? '(unstaged)' : '(staged)')}`);\n }\n\n // No per-file summary: the applied files are visible in the IDE's source control view.\n console.info();\n console.info(\n pc.dim(\n applyUnstaged\n ? ' files are unstaged — review, stage what you want, and commit when ready'\n : ' files are staged — review and commit when ready',\n ),\n );\n console.info();\n}\n","/**\n * Shared contribution engine.\n *\n * Cella (upstream) pulls a fork's branch and detects which files the fork\n * changed, created, or deleted relative to cella's base branch. It then builds\n * a clean local `contrib/<fork>` branch — built on top of the base branch with\n * only the fork's file overlays — so the changes can be reviewed and adopted\n * without a working-tree checkout.\n *\n * The fork's blobs are read directly from the fetched ref (already in cella's\n * object store), never from the filesystem.\n */\n\nimport { dirname, join } from 'node:path';\nimport type { CellaCliConfig, FileStatus } from '../config/types';\nimport { git } from '../utils/git';\nimport { isIgnored, isPinned, isUnderAnyFolder } from '../utils/overrides';\nimport { analyzeRefs, enrichChangeInfo } from './analyze-core';\n\n/** A single contributable file with classification and metadata. */\nexport interface ContribFile {\n /** File path relative to repo root */\n path: string;\n /** How adopting this file changes cella */\n kind: 'modified' | 'created' | 'deleted';\n /** Analyzer status from cella's POV (behind = fork ahead, diverged = both changed) */\n status: FileStatus;\n /** Relative date of the fork's change (e.g. '3 days ago') */\n changedAt?: string;\n /** Unix epoch seconds of the fork's change, for sorting */\n changedTs?: number;\n}\n\n/** Files a fork contributes relative to the base branch. */\nexport interface ContribDetection {\n /** Files changed in fork that also exist in base */\n modified: string[];\n /** New fork files in directories that exist in base (sibling heuristic) */\n created: string[];\n /** Files that exist in base but were removed in fork */\n deleted: string[];\n /** Enriched per-file metadata for the union of the above */\n files: ContribFile[];\n}\n\n/**\n * List all files tracked at a ref.\n */\nasync function listFilesAtRef(repoPath: string, ref: string): Promise<Set<string>> {\n const raw = await git(['ls-tree', '-r', '--name-only', ref], repoPath);\n return new Set(raw.split('\\n').filter(Boolean));\n}\n\n/**\n * Detect the files a fork contributes relative to cella's base branch.\n *\n * Uses a merge-base 3-way analysis (cella = local, fork = incoming) so the\n * result distinguishes fork-ahead changes from cella's own drift. Only files\n * where the fork is ahead (status `behind`) or both sides changed (`diverged`)\n * are contributable.\n *\n * @param repoPath - Cella repo path (where the fork ref has been fetched)\n * @param baseRef - Cella's base branch ref (e.g. 'development')\n * @param forkRef - Fetched fork commit (e.g. a resolved FETCH_HEAD sha)\n * @param config - Cella's config, used to exclude ignored/pinned files\n * @param forkTerritory - Paths the fork owns (from the fork's own\n * `ignored` list); excluded so fork-specific modules aren't offered back\n */\nexport async function detectContributableFiles(\n repoPath: string,\n baseRef: string,\n forkRef: string,\n config: CellaCliConfig,\n forkTerritory: string[] = [],\n): Promise<ContribDetection> {\n // Common ancestor for 3-way comparison; fall back to baseRef if histories are unrelated\n const mergeBase = (await git(['merge-base', baseRef, forkRef], repoPath, { ignoreErrors: true })).trim() || baseRef;\n\n const predicates = {\n isIgnored: (path: string) => isIgnored(path, config) || isUnderAnyFolder(path, forkTerritory),\n isPinned: (path: string) => isPinned(path, config),\n };\n\n // local = cella (baseRef), incoming = fork (forkRef)\n const analyzed = await analyzeRefs(repoPath, baseRef, forkRef, mergeBase, predicates);\n await enrichChangeInfo(repoPath, analyzed, mergeBase, baseRef, forkRef);\n\n // Base directory set for the sibling heuristic on created files.\n // Seed with '.' because the repo root always exists in cella, so new fork\n // files at the root (e.g. a shared config) are offered rather than silently skipped.\n const baseFiles = await listFilesAtRef(repoPath, baseRef);\n const baseDirs = new Set<string>(['.']);\n for (const f of baseFiles) {\n let dir = dirname(f);\n while (dir !== '.') {\n baseDirs.add(dir);\n dir = dirname(dir);\n }\n }\n\n const files: ContribFile[] = [];\n for (const file of analyzed) {\n // Only files where the fork is ahead of cella are contributable\n if (file.status !== 'behind' && file.status !== 'diverged') continue;\n if (file.isIgnored || file.isPinned) continue;\n\n const inCella = file.existsInFork; // local side\n const inFork = file.existsInUpstream; // incoming side\n\n let kind: ContribFile['kind'];\n if (inCella && !inFork) {\n kind = 'deleted';\n } else if (!inCella && inFork) {\n // New fork file: only offer it when its directory already exists in cella,\n // so fork-specific modules don't flood the list (territory handles the rest)\n if (!baseDirs.has(dirname(file.path))) continue;\n kind = 'created';\n } else {\n kind = 'modified';\n }\n\n // Fork-side change date: 'behind' stores it in changedAt, 'diverged' in upstreamChangedAt\n const changedAt = file.status === 'diverged' ? file.upstreamChangedAt : file.changedAt;\n const changedTs = file.status === 'diverged' ? file.upstreamChangedTs : file.changedTs;\n files.push({ path: file.path, kind, status: file.status, changedAt, changedTs });\n }\n\n return {\n modified: files.filter((f) => f.kind === 'modified').map((f) => f.path),\n created: files.filter((f) => f.kind === 'created').map((f) => f.path),\n deleted: files.filter((f) => f.kind === 'deleted').map((f) => f.path),\n files,\n };\n}\n\n/** Total number of files in a detection result. */\nexport function countDetection(detection: ContribDetection): number {\n return detection.modified.length + detection.created.length + detection.deleted.length;\n}\n\n/**\n * Read mode and blob hash for a file at a ref.\n * Returns null if the path is not a regular blob at the ref.\n */\nasync function readBlobInfo(\n repoPath: string,\n ref: string,\n filePath: string,\n): Promise<{ mode: string; hash: string } | null> {\n const line = await git(['ls-tree', ref, '--', filePath], repoPath, { ignoreErrors: true });\n if (!line) return null;\n // Format: \"<mode> <type> <hash>\\t<path>\"\n const match = line.match(/^(\\d{6}) (\\w+) ([0-9a-f]+)\\t/);\n if (!match) return null;\n const [, mode, type, hash] = match;\n if (type !== 'blob') return null;\n // Only allow regular (100644) and executable (100755) file modes; skip symlinks/gitlinks\n if (mode !== '100644' && mode !== '100755') return null;\n return { mode, hash };\n}\n\n/**\n * Build a clean local `contrib/<fork>` branch from a fork's contributed files.\n *\n * The branch is created on top of `baseRef` with only the fork's file overlays\n * applied via a temporary index — the working tree is never touched.\n *\n * @returns The branch name and number of files applied.\n */\nexport async function buildContribBranch(\n repoPath: string,\n baseRef: string,\n forkRef: string,\n detection: ContribDetection,\n forkName: string,\n): Promise<{ branch: string; appliedFiles: string[] }> {\n const branch = `contrib/${forkName}`;\n const tmpIndex = join(repoPath, '.git', `tmp-contrib-index-${forkName.replace(/[^\\w.-]/g, '_')}`);\n const indexEnv = { GIT_INDEX_FILE: tmpIndex };\n\n try {\n // Seed the temp index with cella's base tree\n await git(['read-tree', baseRef], repoPath, { env: indexEnv });\n\n const appliedFiles: string[] = [];\n\n // Overlay modified + created fork files (blobs already in object store via fetch)\n for (const filePath of [...detection.modified, ...detection.created]) {\n const blob = await readBlobInfo(repoPath, forkRef, filePath);\n if (!blob) continue;\n await git(\n ['update-index', '--add', '--replace', '--cacheinfo', `${blob.mode},${blob.hash},${filePath}`],\n repoPath,\n {\n env: indexEnv,\n },\n );\n appliedFiles.push(filePath);\n }\n\n // Remove deleted files from the index\n for (const filePath of detection.deleted) {\n await git(['update-index', '--remove', filePath], repoPath, { env: indexEnv, ignoreErrors: true });\n appliedFiles.push(`(deleted) ${filePath}`);\n }\n\n if (appliedFiles.length === 0) {\n return { branch, appliedFiles };\n }\n\n // Write tree and commit on top of base\n const treeHash = await git(['write-tree'], repoPath, { env: indexEnv });\n const parentHash = await git(['rev-parse', baseRef], repoPath);\n const commitBody = appliedFiles.map((f) => `- ${f}`).join('\\n');\n const commitMessage = `contrib(${forkName}): ${appliedFiles.length} files\\n\\n${commitBody}`;\n const commitHash = await git(['commit-tree', treeHash, '-p', parentHash, '-m', commitMessage], repoPath);\n\n // Create/update the local branch ref without checkout\n await git(['update-ref', `refs/heads/${branch}`, commitHash], repoPath);\n\n return { branch, appliedFiles };\n } finally {\n try {\n const { unlinkSync } = await import('node:fs');\n unlinkSync(tmpIndex);\n } catch {\n // Best effort\n }\n }\n}\n","/**\n * Shared helpers for the fork-aware services (`forks` and `contributions`).\n */\n\nimport { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport type { ForkConfig } from '../config/types';\nimport pc from '../utils/colors';\n\n/** A fork config paired with its validation result. */\nexport interface ValidatedFork {\n fork: ForkConfig;\n resolvedPath: string;\n valid: boolean;\n error?: string;\n}\n\n/**\n * Validate a fork's local path resolves safely and points at a git repository.\n *\n * @param requireConfig when true, the fork must also contain a `cella.config.ts`.\n */\nexport function validateForkPath(fork: ForkConfig, basePath: string, requireConfig = false): ValidatedFork {\n const resolvedPath = resolve(basePath, fork.localPath);\n\n // Validate resolved path doesn't escape the parent directory via traversal (CWE-22)\n if (!resolvedPath.startsWith(resolve(basePath, '..'))) {\n return { fork, resolvedPath, valid: false, error: 'path resolves outside parent directory' };\n }\n if (!existsSync(resolvedPath)) return { fork, resolvedPath, valid: false, error: 'path does not exist' };\n if (!existsSync(`${resolvedPath}/.git`)) return { fork, resolvedPath, valid: false, error: 'not a git repository' };\n if (requireConfig && !existsSync(`${resolvedPath}/cella.config.ts`)) {\n return { fork, resolvedPath, valid: false, error: 'missing cella.config.ts' };\n }\n\n return { fork, resolvedPath, valid: true };\n}\n\n/**\n * Print the \"no forks configured\" empty-state with a config example.\n *\n * @param action a short dim line describing what forks enable (e.g. 'add forks to your config:').\n */\nexport function printNoForksHint(action: string): void {\n console.info(pc.yellow('no forks configured in cella.config.ts'));\n console.info(pc.dim(action));\n console.info(pc.dim(` forks: [{ name: 'my-app', localPath: '../my-app', pullBranch: 'development' }]`));\n}\n","/**\n * Forks service for sync CLI v2.\n *\n * Allows syncing to multiple local fork repositories from an upstream template.\n * Selecting a fork immediately runs sync (+ packages if enabled), then returns to selection.\n */\n\nimport { resolve } from 'node:path';\nimport process from 'node:process';\nimport { Separator, select } from '@inquirer/prompts';\nimport type { ForkConfig, RuntimeConfig } from '../config/types';\nimport pc from '../utils/colors';\nimport { loadConfig, resolveUpstream } from '../utils/config';\nimport { getCommitInfo, getCurrentBranch, getStoredSyncRef, git } from '../utils/git';\nimport { printNoForksHint, validateForkPath } from './fork-utils';\nimport { runSyncCommand } from './sync';\n\n/** Status info gathered from a fork repository */\ninterface ForkStatus {\n branch: string;\n dirty: number;\n lastSync: { date: string; message: string } | null;\n}\n\n/**\n * Gather git status info for a fork: branch, dirty state, last sync.\n */\nasync function gatherForkStatus(forkPath: string): Promise<ForkStatus> {\n const [branch, porcelain, syncRef] = await Promise.all([\n getCurrentBranch(forkPath).catch(() => 'unknown'),\n git(['status', '--porcelain'], forkPath, { ignoreErrors: true }),\n getStoredSyncRef(forkPath),\n ]);\n\n const dirty = porcelain ? porcelain.split('\\n').filter(Boolean).length : 0;\n\n let lastSync: { date: string; message: string } | null = null;\n if (syncRef) {\n const commitInfo = await getCommitInfo(forkPath, syncRef).catch(() => null);\n lastSync = { date: commitInfo?.date ?? 'unknown', message: commitInfo?.message ?? '' };\n }\n\n return { branch, dirty, lastSync };\n}\n\n/**\n * Format a fork choice label with status info.\n */\nfunction formatForkChoice(name: string, status: ForkStatus | null): string {\n if (!status) return name;\n\n // Sync: date and truncated commit message.\n let syncPart: string;\n if (status.lastSync) {\n const msg =\n status.lastSync.message.length > 36 ? `${status.lastSync.message.slice(0, 36)}…` : status.lastSync.message;\n syncPart = pc.dim(`${status.lastSync.date}`);\n if (msg) syncPart += pc.dim(` '${msg}'`);\n } else {\n syncPart = pc.dim('never synced');\n }\n\n // Dirty state: only show if there are uncommitted changes\n const dirtyPart = status.dirty > 0 ? pc.yellow(`${status.dirty} uncommitted`) : '';\n\n const parts = [name, pc.dim(`[${status.branch}]`), syncPart];\n if (dirtyPart) parts.push(dirtyPart);\n\n return parts.join(pc.dim(' · '));\n}\n\n/**\n * Build fork choices with live status info gathered in parallel.\n */\nasync function buildForkChoices(\n forks: ForkConfig[],\n basePath: string,\n): Promise<Array<{ value: string; name: string; disabled?: string }>> {\n const validated = forks.map((fork) => validateForkPath(fork, basePath, true));\n\n // Gather status for all valid forks in parallel\n const statusEntries = await Promise.all(\n validated\n .filter((v) => v.valid)\n .map(async (v) => {\n const status = await gatherForkStatus(v.resolvedPath);\n return { path: v.fork.localPath, status };\n }),\n );\n const statusMap = new Map(statusEntries.map((e) => [e.path, e.status]));\n\n return validated.map((v) => {\n if (!v.valid) {\n return {\n value: v.fork.localPath,\n name: `${v.fork.name} ${pc.dim(v.fork.localPath)}`,\n disabled: v.error,\n };\n }\n return {\n value: v.fork.localPath,\n name: formatForkChoice(v.fork.name, statusMap.get(v.fork.localPath) ?? null),\n };\n });\n}\n\n/**\n * Sync a single fork by running the same command flow the fork owner would run locally.\n */\nasync function syncFork(config: RuntimeConfig, fork: ForkConfig, forkPath: string): Promise<void> {\n console.info();\n console.info(pc.cyan(`syncing to ${fork.name}...`));\n console.info(pc.dim(`path: ${forkPath}`));\n console.info();\n\n const forkConfig = await loadConfig(forkPath);\n\n // Build runtime config for the fork.\n const { branchRef } = resolveUpstream(forkConfig.settings);\n const upstreamRef = branchRef;\n\n const forkRuntimeConfig: RuntimeConfig = {\n ...forkConfig,\n forkPath,\n upstreamRef,\n service: 'sync',\n logFile: config.logFile,\n list: false,\n json: false,\n verbose: config.verbose,\n hard: config.hard,\n };\n\n await runSyncCommand(forkRuntimeConfig);\n}\n\n/**\n * Run the forks service.\n *\n * Lists configured forks. Selecting a fork runs sync immediately,\n * then returns to the selection menu.\n */\nexport async function runForks(config: RuntimeConfig): Promise<void> {\n const forks = config.forks ?? [];\n\n if (forks.length === 0) {\n printNoForksHint('add forks to your config:');\n return;\n }\n\n // Non-interactive mode via --fork flag\n if (config.fork) {\n const match = forks.find((f) => f.name === config.fork);\n if (!match) {\n console.error(pc.red(`fork '${config.fork}' not found in config`));\n return;\n }\n const resolvedPath = resolve(config.forkPath, match.localPath);\n await syncFork(config, match, resolvedPath);\n return;\n }\n\n // Interactive loop: select fork → sync → return to selection\n // Choices are rebuilt each iteration to reflect updated status\n while (true) {\n const choices = await buildForkChoices(forks, config.forkPath);\n const forkChoices = [...choices, new Separator('─'.repeat(40)), { value: '_exit', name: pc.dim('exit') }];\n\n const selectedPath = await select<string>({\n message: 'select fork to sync:',\n choices: forkChoices,\n loop: false,\n });\n\n if (selectedPath === '_exit') {\n process.exit(0);\n }\n\n const resolvedForkPath = resolve(config.forkPath, selectedPath);\n const selectedFork = forks.find((f) => f.localPath === selectedPath);\n if (!selectedFork) {\n console.error(pc.red(`fork '${selectedPath}' not found in config`));\n continue;\n }\n\n await syncFork(config, selectedFork, resolvedForkPath);\n\n console.info();\n }\n}\n","/**\n * Sync service for the cella CLI.\n *\n * Runs the merge engine directly in the fork (no worktree) so conflicts surface in the IDE, on\n * a fresh temporary branch cut from the trunk. The command is idempotent: if a run stops at\n * conflicts, resolve them and run `cella sync` again to finish the same merge.\n */\n\nimport { spawnSync } from 'node:child_process';\nimport { select } from '@inquirer/prompts';\nimport type { MergeResult, RuntimeConfig } from '../config/types';\nimport pc from '../utils/colors';\nimport {\n buildTemporarySyncBranch,\n DEFAULT_SYNC_PREFIX,\n isTemporarySyncBranch,\n resolveReleaseBase,\n} from '../utils/config';\nimport {\n createSpinner,\n printFlagWarnings,\n printSummary,\n printSyncComplete,\n spinnerFail,\n spinnerSuccess,\n spinnerText,\n warningMark,\n writeLogFile,\n} from '../utils/display';\nimport { closePr, type GhPullRequest, ghAvailable, listOpenSyncPrs, mergePrSquash } from '../utils/gh';\nimport {\n assertClean,\n type CommitRangeEntry,\n commitSquash,\n countCommitsBetween,\n createBranchFrom,\n deleteBranch,\n flattenBranch,\n getCommitInfo,\n getConflictedFiles,\n getCurrentBranch,\n getMergeBase,\n getShortSha,\n getUpstreamStatus,\n isClean,\n listBranchMergeCommits,\n listCommitsBetween,\n mergeInProgress,\n pullFastForward,\n pushBranch,\n readManifestAtRef,\n readManifestBaseAtRef,\n readPackageVersionAtRef,\n stageAll,\n switchBranch,\n} from '../utils/git';\nimport { readSyncManifest } from '../utils/manifest';\nimport { runMergeEngine } from './merge-engine';\nimport { runPackages } from './packages';\n\n/** Context for the temporary branch a sync cycle runs on. */\ninterface TemporarySyncBranch {\n /** The freshly cut temporary branch, e.g. `cella/sync/20260702-1430`. */\n temporaryBranch: string;\n /** The trunk the branch was cut from and PRs land into (`releaseBase`, default `main`). */\n base: string;\n /** The branch the user was on before the cycle started (for cleanup on no-op). */\n startBranch: string;\n}\n\n/**\n * Make sure the trunk is current with its remote before a sync cycle cuts a branch from it.\n *\n * Fetches the trunk's upstream and reacts to how local compares:\n * - behind (fast-forwardable): fast-forward it so the branch is cut from the latest trunk.\n * - diverged (local commits the remote lacks *and* vice versa): abort with guidance, since\n * syncing onto a stale/diverged trunk produces a PR against an out-of-date base and avoidable\n * conflicts.\n * - ahead-only / up to date / no upstream (local-only repo): fine, just note it and continue.\n */\nasync function ensureBaseUpToDate(forkPath: string, base: string): Promise<void> {\n const { upstream, ahead, behind } = await getUpstreamStatus(forkPath);\n\n if (!upstream) {\n console.info(pc.dim(`'${base}' has no upstream — skipping the up-to-date check.`));\n return;\n }\n\n if (ahead > 0 && behind > 0) {\n throw new Error(\n `'${base}' has diverged from '${upstream}' (${ahead} ahead, ${behind} behind).\\n` +\n `Reconcile '${base}' with '${upstream}' first (e.g. rebase or reset it), then re-run sync.`,\n );\n }\n\n if (behind > 0) {\n console.info(pc.dim(`fast-forwarding '${base}' to '${upstream}' (${behind} behind)...`));\n await pullFastForward(forkPath);\n return;\n }\n\n if (ahead > 0) {\n console.info(pc.dim(`'${base}' is ${ahead} commit(s) ahead of '${upstream}' (unpushed) — continuing.`));\n }\n}\n\n/**\n * Cut a fresh temporary sync branch from the trunk.\n *\n * Switches to `releaseBase`, fast-forwards it, then creates `cella/sync/<stamp>` so the\n * merge lands on an isolated throwaway branch rather than a long-lived integration branch.\n */\nasync function setupTemporarySyncBranch(config: RuntimeConfig): Promise<TemporarySyncBranch> {\n const { forkPath, settings } = config;\n const base = resolveReleaseBase(settings);\n const startBranch = await getCurrentBranch(forkPath);\n\n console.info(pc.dim(`switching to '${base}' and updating...`));\n await switchBranch(forkPath, base);\n await ensureBaseUpToDate(forkPath, base);\n\n const temporaryBranch = buildTemporarySyncBranch();\n\n console.info(pc.dim(`creating temporary sync branch '${temporaryBranch}' from '${base}'...`));\n console.info();\n await createBranchFrom(forkPath, temporaryBranch, base);\n\n return { temporaryBranch, base, startBranch };\n}\n\n/**\n * Run the merge engine against the current branch (the core merge step).\n *\n * Performs the merge directly in the fork and leaves it staged: conflicted files keep their\n * markers for IDE 3-way resolution, everything else is resolved per the override rules. Called\n * by `runSyncCycle` and by the forks service.\n */\nexport async function runSync(\n config: RuntimeConfig,\n options?: {\n stagedBranch?: string;\n },\n): Promise<MergeResult> {\n createSpinner('starting sync...');\n\n const result = await runMergeEngine(config, {\n apply: true,\n onProgress: (message) => {\n spinnerText(message);\n },\n onStep: (label, detail) => {\n spinnerSuccess(label, detail);\n createSpinner('...');\n },\n });\n\n if (result.success) {\n spinnerSuccess();\n } else {\n spinnerFail('sync completed with conflicts');\n }\n\n // Print summary only (no file lists for sync)\n printSummary(result.summary, 'merge summary');\n\n // Write log file if requested\n if (config.logFile) {\n const logPath = writeLogFile(config.forkPath, result.files);\n console.info();\n console.info(pc.dim(`full file list written to: ${logPath}`));\n }\n\n const stagedBranch =\n options?.stagedBranch && result.conflicts.length === 0 && hasStagedSyncChanges(result)\n ? options.stagedBranch\n : undefined;\n printSyncComplete(result, { stagedBranch });\n\n printFlagWarnings({ hard: config.hard, unpinned: config.unpinned });\n\n return result;\n}\n\n/** Conventional PR title prefix required by release-please. */\nconst SYNC_PR_TITLE = 'chore: sync upstream cella';\n\n/** Most recent upstream commits listed in a sync PR body (mirrors the engine's fetch display cap). */\nconst PR_BODY_COMMIT_MAX = 50;\n\n/**\n * Build the sync commit subject, e.g. `chore: sync upstream cella v0.2.2 (4f7d87c)`.\n *\n * The upstream version comes from the manifest's release tag when tracking releases, else from\n * upstream's root package.json at the merged commit. Falls back to the bare title (+ short sha)\n * when a lookup fails, so committing never blocks on cosmetics.\n */\nasync function buildSyncCommitMessage(forkPath: string, upstreamRef: string): Promise<string> {\n const shortSha = await getShortSha(forkPath, upstreamRef).catch(() => '');\n if (!shortSha) return SYNC_PR_TITLE;\n\n const manifest = await readSyncManifest(forkPath);\n const version =\n manifest?.upstream.release ?? (await readPackageVersionAtRef(forkPath, upstreamRef).catch(() => null));\n return version ? `${SYNC_PR_TITLE} v${version.replace(/^v/, '')} (${shortSha})` : `${SYNC_PR_TITLE} ${shortSha}`;\n}\n\n/**\n * Qualify bare `#123` references in an upstream commit subject with the upstream repo slug.\n * Left bare, GitHub would auto-link them to the fork's own issue/PR #123 in the PR body.\n */\nfunction qualifyPrRefs(subject: string, repoSlug?: string): string {\n if (!repoSlug) return subject;\n return subject.replace(/(^|[^\\w/])#(\\d+)\\b/g, `$1${repoSlug}#$2`);\n}\n\n/** Inputs for {@link buildSyncPrBody}, recovered from the committed sync manifests. */\nexport interface SyncPrBodyInput {\n /** GitHub slug of the upstream repo, e.g. 'cellajs/cella'. */\n repoSlug?: string;\n /** Upstream version or release tag at the sync point (leading `v` optional). */\n version?: string | null;\n /** Previous upstream sync point (full sha), when known. */\n fromSha?: string | null;\n /** Upstream commit this sync moved to (full sha). */\n toSha: string;\n /** Upstream commits in the range, oldest first (possibly truncated to the newest N). */\n commits: CommitRangeEntry[];\n /** Total commits in the range (may exceed `commits.length` when truncated). */\n totalCount: number;\n}\n\n/** Render the sync PR body: where the sync moved to, plus the upstream commits it brought in. */\nexport function buildSyncPrBody(input: SyncPrBodyInput): string {\n const { repoSlug, version, fromSha, toSha, commits, totalCount } = input;\n const githubUrl = repoSlug ? `https://github.com/${repoSlug}` : undefined;\n const short = (sha: string) => sha.slice(0, 7);\n const commitRef = (sha: string) =>\n githubUrl ? `[\\`${short(sha)}\\`](${githubUrl}/commit/${sha})` : `\\`${short(sha)}\\``;\n\n const upstreamName = githubUrl ? `[${repoSlug}](${githubUrl})` : 'cella';\n const versionSuffix = version ? ` (v${version.replace(/^v/, '')})` : '';\n const lines = [`Syncs upstream ${upstreamName} to ${commitRef(toSha)}${versionSuffix}.`];\n\n if (totalCount > 0 && fromSha) {\n const compare = githubUrl ? ` ([compare](${githubUrl}/compare/${short(fromSha)}...${short(toSha)}))` : '';\n lines.push('', `**${totalCount} upstream commit${totalCount === 1 ? '' : 's'} since last sync**${compare}:`, '');\n if (totalCount > commits.length) lines.push(`- …${totalCount - commits.length} earlier commit(s) not shown`);\n for (const commit of commits) {\n lines.push(`- ${commitRef(commit.hash)} ${qualifyPrRefs(commit.message, repoSlug)}`);\n }\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/**\n * Build the PR body for a finished sync branch: the upstream commits between the trunk's last\n * recorded sync point and the one this branch moves to (both read from committed manifests, so\n * this works on the rerun that ships the branch, long after the merge engine ran).\n *\n * Returns undefined when the branch has no committed manifest — the caller falls back to `--fill`.\n */\nasync function buildSyncPrBodyForBranch(forkPath: string, base: string): Promise<string | undefined> {\n const manifest = await readManifestAtRef(forkPath, 'HEAD');\n if (!manifest) return undefined;\n\n const toSha = manifest.upstream.commit.toLowerCase();\n // The trunk's committed manifest is the previous sync point; merge-base covers forks whose\n // last sync predates the manifest. `refs/cella/last-sync` is no help here: the merge already\n // moved it to `toSha`.\n const fromSha =\n (await readManifestBaseAtRef(forkPath, base)) ?? (await getMergeBase(forkPath, base, toSha).catch(() => null));\n const version = manifest.upstream.release ?? (await readPackageVersionAtRef(forkPath, toSha).catch(() => null));\n\n const totalCount = fromSha ? await countCommitsBetween(forkPath, fromSha, toSha).catch(() => 0) : 0;\n const commits =\n fromSha && totalCount > 0\n ? await listCommitsBetween(forkPath, fromSha, toSha, {\n oldestFirst: true,\n skip: totalCount > PR_BODY_COMMIT_MAX ? totalCount - PR_BODY_COMMIT_MAX : 0,\n limit: PR_BODY_COMMIT_MAX,\n })\n : [];\n\n return buildSyncPrBody({ repoSlug: manifest.upstream.repo, version, fromSha, toSha, commits, totalCount });\n}\n\n/** Print the GitHub CLI command for opening the finished sync PR. */\nfunction printPrCreateStep(branch: string, base: string, title = SYNC_PR_TITLE): void {\n console.info(pc.dim(` gh pr create --base ${base} --head ${branch} --title \"${title}\" --fill`));\n}\n\n/** Print the \"push + open a PR\" steps for a sync branch whose merge is already committed. */\nfunction printShipSteps(temporaryBranch: string, base: string, title?: string): void {\n console.info(pc.dim(` git push -u origin ${temporaryBranch}`));\n printPrCreateStep(temporaryBranch, base, title);\n}\n\n/** Guidance shown after a fresh cycle stages a merge: re-run to finish and ship it. */\nfunction printFinishSteps(): void {\n console.info(pc.dim(' pnpm cella sync'));\n}\n\n/** Whether sync applied changes that need a finishing rerun. */\nfunction hasStagedSyncChanges(result: MergeResult): boolean {\n return result.files.some((file) => ['behind', 'diverged', 'renamed', 'ignored', 'pinned'].includes(file.status));\n}\n\n/** Extract the first URL from command output, usually the PR URL emitted by GitHub CLI. */\nfunction extractFirstUrl(output: string): string | undefined {\n return output.match(/https?:\\/\\/\\S+/)?.[0];\n}\n\n/**\n * Safety net run before a sync branch goes public: flatten away merge commits.\n *\n * The finishing rerun commits the sync as a single-parent commit (`commitSquash`), but a manual\n * `git commit` while the merge is staged records a two-parent merge commit instead. Upstream's\n * history isn't shared with `origin` (sync PRs are squash-merged), so such a commit makes the PR\n * list every upstream commit ever made — and that list grows with every upstream release.\n *\n * When the branch contains merge commits, rewrite it as one commit with identical content\n * (the PR diff is unchanged). Returns true if the branch was rewritten, so the caller can\n * force-push over a previously pushed version.\n */\nasync function flattenSyncBranch(forkPath: string, branch: string, base: string): Promise<boolean> {\n const mergeCommits = await listBranchMergeCommits(forkPath, base);\n if (mergeCommits.length === 0) return false;\n\n // The most recent merge's second parent is the upstream tip that was merged in.\n const message = await buildSyncCommitMessage(forkPath, `${mergeCommits[0]}^2`);\n\n console.info(\n pc.yellow(\n `'${branch}' contains ${mergeCommits.length} merge commit(s) — the PR would list the entire upstream history.`,\n ),\n );\n console.info(pc.dim(`flattening '${branch}' to a single commit (same content)...`));\n await flattenBranch(forkPath, base, message);\n return true;\n}\n\n/** Indent every line of `text` by two spaces, for nesting captured `gh` output under a message. */\nfunction indentLines(text: string): string {\n return text\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n}\n\n/**\n * Turn on GitHub auto-merge (squash) for the just-opened sync PR: it merges itself once required\n * checks pass, so `--direct-merge` needs no babysitting. Returns whether it was enabled; on failure\n * (the repo doesn't allow auto-merge, `gh` too old) it prints the manual command and returns false.\n */\nfunction enableAutoMerge(forkPath: string, branch: string): boolean {\n console.info(pc.dim('enabling auto-merge (squash) once checks pass...'));\n const merge = mergePrSquash(forkPath, branch, { auto: true, deleteBranch: true });\n if (merge.ok) return true;\n\n console.info(pc.yellow('could not enable auto-merge (is it enabled for the repo?). merge it manually:'));\n if (merge.output) console.info(pc.dim(indentLines(merge.output)));\n console.info(pc.dim(` gh pr merge ${branch} --squash --delete-branch`));\n return false;\n}\n\n/**\n * Push the finished sync branch to `origin`, open a PR into the trunk, and switch back to the\n * trunk. Runs automatically once a rerun completes the merge cleanly.\n *\n * Before pushing, any merge commits on the branch are flattened away (see `flattenSyncBranch`)\n * so the PR never lists the upstream branch's entire history.\n *\n * With `--direct-merge`, once the PR is open GitHub auto-merge is enabled (see `enableAutoMerge`)\n * so it squash-merges itself as soon as required checks pass — no forgotten open PR to trip over.\n *\n * Every step degrades gracefully: a failed push (no `origin`, auth) prints the manual steps and\n * leaves you on the branch; a missing/failed `gh` (or an existing PR) prints the `gh` command but\n * still returns you to the trunk since the branch is already pushed.\n */\nasync function shipSyncBranch(config: RuntimeConfig, branch: string): Promise<void> {\n const { forkPath, settings } = config;\n const base = resolveReleaseBase(settings);\n\n const flattened = await flattenSyncBranch(forkPath, branch, base);\n let prUrl: string | undefined;\n let prOpened = false;\n let autoMergeEnabled = false;\n\n // The squash commit's subject is the versioned sync message — reuse it as the PR title so the\n // PR name carries the upstream version and commit id (release-please only needs the prefix).\n const headSubject = (await getCommitInfo(forkPath, 'HEAD').catch(() => null))?.message;\n const prTitle = headSubject?.startsWith(SYNC_PR_TITLE) ? headSubject : SYNC_PR_TITLE;\n\n console.info(pc.dim(`pushing '${branch}' to origin...`));\n try {\n await pushBranch(forkPath, 'origin', branch, { forceWithLease: flattened });\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n console.info(pc.yellow(`push failed (${detail.split('\\n')[0]}). finish manually:`));\n printShipSteps(branch, base, prTitle);\n return;\n }\n\n if (ghAvailable()) {\n console.info(pc.dim('opening a pull request...'));\n const prBody = await buildSyncPrBodyForBranch(forkPath, base);\n const bodyArgs = prBody ? ['--body', prBody] : ['--fill'];\n const pr = spawnSync('gh', ['pr', 'create', '--base', base, '--head', branch, '--title', prTitle, ...bodyArgs], {\n cwd: forkPath,\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n prUrl = extractFirstUrl(`${pr.stdout ?? ''}\\n${pr.stderr ?? ''}`);\n prOpened = pr.status === 0;\n if (prOpened) {\n if (config.directMerge) autoMergeEnabled = enableAutoMerge(forkPath, branch);\n } else {\n console.info(pc.yellow('could not open the PR automatically (it may already exist). open it with:'));\n if (prUrl) console.info(pc.dim(` ${prUrl}`));\n printPrCreateStep(branch, base, prTitle);\n }\n } else {\n console.info(pc.yellow('`gh` not found — open the PR manually:'));\n printPrCreateStep(branch, base, prTitle);\n }\n\n console.info(pc.dim(`switching back to '${base}'...`));\n await switchBranch(forkPath, base);\n await pullFastForward(forkPath).catch(() => {});\n\n console.info();\n if (prUrl) {\n console.info(`${pc.green('✓')} Sync pull request ${prOpened ? 'opened' : 'ready'}`);\n const status = autoMergeEnabled\n ? `auto-merge on — squashes into '${base}' when checks pass`\n : `branch pushed, back on '${base}'`;\n console.info(pc.dim(` ${prUrl} · ${status}`));\n } else {\n console.info(`${pc.green('✓')} Sync branch pushed`);\n console.info(pc.dim(` '${branch}' is on origin, back on '${base}'`));\n }\n}\n\n/**\n * Reconcile dependencies and regenerate derived files before committing a resumed merge.\n *\n * A sync merge (plus package.json key-sync) changes `package.json`, which leaves the lockfile\n * and generated files (SDK, etc.) stale and often unstaged. Mirroring what lefthook would do —\n * but up front — we run `pnpm install` then `pnpm check`, so the merge commit is complete and\n * consistent. Returns false if a step fails (the merge is left in progress to retry).\n */\nfunction finalizeWorkspace(forkPath: string): boolean {\n for (const args of [['install'], ['check']]) {\n console.info(pc.dim(`running pnpm ${args.join(' ')}...`));\n const result = spawnSync('pnpm', args, { cwd: forkPath, stdio: 'inherit' });\n if (result.status !== 0) return false;\n }\n return true;\n}\n\n/** Outcome of a sync cycle run on a fresh temporary branch. */\ntype SyncCycleOutcome =\n | { status: 'conflicts'; branch: TemporarySyncBranch }\n | { status: 'staged'; branch: TemporarySyncBranch }\n | { status: 'noop' };\n\n/**\n * Run one sync cycle on a fresh temporary branch: cut the branch, merge upstream (+ packages),\n * and report the resulting state.\n *\n * - `conflicts`: merge staged with unresolved conflicts, left for IDE resolution.\n * - `staged`: clean merge staged, ready to commit.\n * - `noop`: upstream had nothing new; the throwaway branch was deleted and the original branch\n * restored.\n */\nasync function runSyncCycle(config: RuntimeConfig): Promise<SyncCycleOutcome> {\n const { forkPath } = config;\n const branch = await setupTemporarySyncBranch(config);\n\n const result = await runSync(config, { stagedBranch: branch.temporaryBranch });\n\n if (config.settings.syncWithPackages !== false) {\n // Run package sync even when the merge left conflicts: package.json files that are\n // themselves conflicted are skipped and reported; all others are still synced.\n await runPackages(config, { conflictedFiles: result.conflicts });\n }\n\n if (result.conflicts.length > 0) return { status: 'conflicts', branch };\n\n // Nothing staged: already up to date. Clean up the throwaway branch.\n if (!mergeInProgress(forkPath)) {\n await switchBranch(forkPath, branch.startBranch === branch.temporaryBranch ? branch.base : branch.startBranch);\n await deleteBranch(forkPath, branch.temporaryBranch);\n return { status: 'noop' };\n }\n\n return { status: 'staged', branch };\n}\n\n/**\n * Finish an in-progress merge left by an earlier `cella sync` run on the same temporary branch.\n *\n * This is what makes the command idempotent: after a run stops at conflicts, resolve and stage\n * them, then run `cella sync` again. If conflicts remain we point them out and stop; once none\n * remain we reconcile dependencies (`pnpm install` + `pnpm check`), stage everything, commit the\n * staged delta as a single squashed commit (see `commitSquash`), then push the branch and open\n * the PR (see `shipSyncBranch`).\n */\nasync function resumeSyncMerge(config: RuntimeConfig, branch: string): Promise<void> {\n const { forkPath } = config;\n const conflicts = await getConflictedFiles(forkPath);\n\n console.info();\n if (conflicts.length > 0) {\n console.info(pc.yellow(`${conflicts.length} file(s) still conflict on '${branch}':`));\n for (const file of conflicts) console.info(pc.dim(` ${file}`));\n console.info(pc.dim('resolve and stage them, then re-run `pnpm cella sync` to finish (it commits for you).'));\n return;\n }\n\n // Stage everything up front (resolved conflicts + any manual edits) before running tooling that\n // may fail: `finalizeWorkspace` returns early on a failing `pnpm check`, so staging afterwards\n // would never happen and the edits would never be recorded in the merge.\n await stageAll(forkPath);\n\n // Reconcile deps + regenerate derived files (package.json key-sync and the merge both touch\n // package.json, leaving the lockfile and generated files stale/unstaged).\n if (!finalizeWorkspace(forkPath)) {\n console.info();\n console.info(\n pc.yellow('`pnpm install`/`pnpm check` failed. fix the issues, then re-run `pnpm cella sync` to finish.'),\n );\n return;\n }\n\n // Build the commit subject before squashing (commitSquash clears MERGE_HEAD), re-stage (the\n // install/check step may have touched files), then commit the staged delta as a single-parent\n // commit so the PR shows one clean commit instead of the whole upstream history (the merge's\n // upstream ancestry isn't shared on the remote).\n const message = await buildSyncCommitMessage(forkPath, 'MERGE_HEAD');\n await stageAll(forkPath);\n await commitSquash(forkPath, message);\n console.info();\n console.info(pc.green(`committed the sync on '${branch}' as '${message}'.`));\n await shipSyncBranch(config, branch);\n}\n\n/**\n * Merge the open sync PR(s) so the trunk carries the recorded sync point before a new cycle cuts\n * from it. The newest PR is a content superset of any older ones (each cycle re-syncs from the\n * same stale trunk base), so the newest is squash-merged and the rest are closed.\n *\n * A merge GitHub refuses — conflicts with the trunk, or failing required checks (the \"breaking\n * changes\" to fix first) — stops the run: those must be resolved on the PR before syncing again.\n * On success the trunk is fast-forwarded locally so the fresh cycle cuts from it.\n */\nasync function mergeOpenSyncPrs(config: RuntimeConfig, open: GhPullRequest[]): Promise<'continue' | 'cancel'> {\n const { forkPath, settings } = config;\n const base = resolveReleaseBase(settings);\n const [newest, ...superseded] = open;\n\n console.info();\n console.info(pc.dim(`squash-merging #${newest.number} into '${base}'...`));\n const merged = mergePrSquash(forkPath, newest.number, { deleteBranch: true });\n if (!merged.ok) {\n console.info();\n console.info(pc.yellow(`could not merge #${newest.number} — resolve it first, then re-run \\`pnpm cella sync\\`:`));\n if (merged.output) console.info(pc.dim(indentLines(merged.output)));\n console.info(pc.dim(` ${newest.url}`));\n return 'cancel';\n }\n console.info(`${pc.green('✓')} merged #${newest.number}`);\n // Drop the stale local branch that tracked the merged PR (the remote one went with --delete-branch).\n await deleteBranch(forkPath, newest.headRefName);\n\n for (const pr of superseded) {\n console.info(pc.dim(`closing #${pr.number} — its changes are included in #${newest.number}...`));\n closePr(forkPath, pr.number);\n await deleteBranch(forkPath, pr.headRefName);\n }\n\n // Bring the merged commit into the local trunk so the new cycle cuts from an up-to-date base.\n console.info(pc.dim(`switching to '${base}' and fast-forwarding...`));\n await switchBranch(forkPath, base);\n await pullFastForward(forkPath);\n\n return 'continue';\n}\n\n/**\n * Before cutting a fresh sync branch, warn when an earlier sync PR is still open and unmerged.\n *\n * The last-sync point is recorded in the manifest committed *on the sync branch*, not on the\n * trunk. So a new cycle cut from a trunk that still lacks a merged sync PR re-includes that PR's\n * whole delta on top of the new upstream commits — the \"why are there suddenly so many changes\"\n * surprise. This offers to squash-merge the open PR first (so the new cycle cuts from an\n * up-to-date trunk), continue anyway, or cancel.\n *\n * Degrades to a silent no-op (`continue`) when it can't help: no `gh`, no open sync PR, or a\n * non-interactive session (no TTY to prompt on).\n */\nasync function guardAgainstOpenSyncPr(config: RuntimeConfig): Promise<'continue' | 'cancel'> {\n const { forkPath } = config;\n\n if (!ghAvailable() || !process.stdout.isTTY) return 'continue';\n\n const open = listOpenSyncPrs(forkPath, DEFAULT_SYNC_PREFIX);\n if (open.length === 0) return 'continue';\n\n const many = open.length > 1;\n console.info();\n console.info(\n `${warningMark} ${pc.yellow(`${many ? `${open.length} earlier sync PRs are` : 'an earlier sync PR is'} still open and unmerged:`)}`,\n );\n for (const pr of open) {\n console.info(pc.dim(` #${pr.number} ${pr.title}`));\n console.info(pc.dim(` ${pr.url}`));\n }\n console.info(pc.dim(` starting a new sync now produces a PR that re-includes ${many ? 'these' : 'those'} changes.`));\n console.info();\n\n const choice = await select<'merge' | 'continue' | 'cancel'>({\n message: 'how do you want to proceed?',\n choices: [\n {\n value: 'merge',\n name: `merge ${many ? 'them' : `#${open[0].number}`} first, then sync ${pc.dim('(recommended)')}`,\n },\n { value: 'continue', name: `continue anyway ${pc.dim('(new PR will re-include the unmerged changes)')}` },\n { value: 'cancel', name: pc.red('cancel') },\n ],\n loop: false,\n });\n\n if (choice === 'cancel') return 'cancel';\n if (choice === 'continue') return 'continue';\n return mergeOpenSyncPrs(config, open);\n}\n\n/**\n * Run the standalone `cella sync` command.\n *\n * Idempotent. Behaviour depends on where you are:\n * - On a sync branch with a merge in progress: finish that merge (resume after conflicts), then\n * push and open the PR.\n * - On a sync branch with the merge already committed: push and open the PR (e.g. a previous\n * push failed), then switch back to the trunk.\n * - Anywhere else: require a clean tree, then cut a fresh temporary branch and merge upstream.\n */\nexport async function runSyncCommand(config: RuntimeConfig): Promise<void> {\n const { forkPath } = config;\n const currentBranch = await getCurrentBranch(forkPath);\n const onSyncBranch = isTemporarySyncBranch(currentBranch);\n\n // Resume path: an earlier run left a merge staged on this temporary branch (e.g. after\n // conflicts). Re-running finishes it instead of starting over.\n if (onSyncBranch && mergeInProgress(forkPath)) {\n await resumeSyncMerge(config, currentBranch);\n return;\n }\n\n // On a sync branch with the merge already committed: ship it (push + PR + back to trunk).\n if (onSyncBranch) {\n // shipSyncBranch only pushes HEAD, so any edits made after the squash commit would be silently\n // left out of the pushed branch/PR. Refuse to ship over a dirty tree and make them commit.\n if (!(await isClean(forkPath))) {\n console.info();\n console.info(\n pc.yellow(\n `sync branch '${currentBranch}' has uncommitted changes.\\n` +\n 'commit them first (`git commit --amend --no-edit` or a new commit).',\n ),\n );\n return;\n }\n await shipSyncBranch(config, currentBranch);\n return;\n }\n\n // Fresh cycle: only ever cut the temporary branch from a clean tree.\n await assertClean(forkPath);\n\n // Guard against stacking: if an earlier sync PR is still open, its delta would re-appear in\n // this cycle's PR. Offer to merge it first (or bail) before cutting a new branch.\n if ((await guardAgainstOpenSyncPr(config)) === 'cancel') return;\n\n const outcome = await runSyncCycle(config);\n console.info();\n\n if (outcome.status === 'noop') {\n console.info(pc.green('already up to date with upstream — nothing to sync.'));\n return;\n }\n\n const { temporaryBranch } = outcome.branch;\n if (outcome.status === 'conflicts') {\n console.info(`${warningMark} ${pc.yellow(`conflicts on '${temporaryBranch}'. Resolve and stage them, then:`)}`);\n printFinishSteps();\n console.info(pc.dim(' rerun commits the sync, pushes the branch, and opens a PR.'));\n console.info(pc.dim(' let the rerun commit — a manual `git commit` records a merge commit that bloats the PR.'));\n }\n}\n","/**\n * GitHub CLI (`gh`) helpers for the cella CLI.\n *\n * Thin wrappers around `gh` used by the sync service to list, merge, and close the sync pull\n * requests. Every wrapper degrades gracefully when `gh` is missing or a call fails, so a sync\n * run on a repo without `gh`/`origin` still works — it just skips the PR automation.\n */\n\nimport { spawnSync } from 'node:child_process';\n\n/** An open pull request, as returned by `gh pr list --json`. */\nexport interface GhPullRequest {\n number: number;\n title: string;\n headRefName: string;\n url: string;\n}\n\n/** Result of a `gh` invocation: whether it exited 0, plus its combined stdout+stderr. */\nexport interface GhResult {\n ok: boolean;\n output: string;\n}\n\n/** Whether the GitHub CLI is available on PATH. */\nexport function ghAvailable(): boolean {\n return spawnSync('gh', ['--version'], { stdio: 'ignore' }).status === 0;\n}\n\n/** Run `gh` in `cwd`, capturing stdout+stderr. Never throws. */\nfunction runGh(cwd: string, args: string[]): GhResult {\n const result = spawnSync('gh', args, { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });\n const output = `${result.stdout ?? ''}${result.stderr ?? ''}`.trim();\n return { ok: result.status === 0, output };\n}\n\n/**\n * Keep only the pull requests whose head branch is one of cella's temporary sync branches\n * (under the `<prefix>/` namespace, e.g. `cella/sync/`). Pure — unit-tested.\n */\nexport function filterSyncPrs(prs: GhPullRequest[], prefix: string): GhPullRequest[] {\n return prs.filter((pr) => pr.headRefName.startsWith(`${prefix}/`));\n}\n\n/**\n * List open sync PRs (head branch under `<prefix>/`), newest first (highest PR number).\n * Returns an empty array when `gh` fails (no auth, no origin) so callers degrade to a no-op.\n */\nexport function listOpenSyncPrs(cwd: string, prefix: string): GhPullRequest[] {\n const { ok, output } = runGh(cwd, [\n 'pr',\n 'list',\n '--state',\n 'open',\n '--json',\n 'number,title,headRefName,url',\n '--limit',\n '50',\n ]);\n if (!ok || !output) return [];\n\n let parsed: GhPullRequest[];\n try {\n parsed = JSON.parse(output) as GhPullRequest[];\n } catch {\n return [];\n }\n\n return filterSyncPrs(parsed, prefix).sort((a, b) => b.number - a.number);\n}\n\n/**\n * Build the argv for `gh pr merge`. Pure — unit-tested.\n *\n * `auto` uses GitHub auto-merge (the PR squashes once required checks pass); without it the\n * merge is attempted immediately and fails when the PR is not mergeable.\n */\nexport function buildMergeArgs(ref: string, options: { auto?: boolean; deleteBranch?: boolean } = {}): string[] {\n const args = ['pr', 'merge', ref, '--squash'];\n if (options.auto) args.push('--auto');\n if (options.deleteBranch) args.push('--delete-branch');\n return args;\n}\n\n/** Squash-merge a PR (by number, branch, or URL). See {@link buildMergeArgs}. */\nexport function mergePrSquash(\n cwd: string,\n ref: string | number,\n options: { auto?: boolean; deleteBranch?: boolean } = {},\n): GhResult {\n return runGh(cwd, buildMergeArgs(String(ref), options));\n}\n\n/** Close a PR without merging (used to discard superseded sync PRs). */\nexport function closePr(cwd: string, ref: string | number): GhResult {\n return runGh(cwd, ['pr', 'close', String(ref)]);\n}\n","/**\n * Packages service for sync CLI v2.\n *\n * Syncs package.json keys between fork and upstream using safe merge logic:\n * - Add-only: new entries from upstream are added\n * - Bump-only: versions are only upgraded, never downgraded\n * - Never remove: fork entries not in upstream are preserved\n * - Supports nested `pnpm` key (overrides, patchedDependencies, packageExtensions)\n */\n\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { PackageJsonSyncKey, RuntimeConfig } from '../config/types';\nimport pc from '../utils/colors';\nimport { createSpinner, spinnerSuccess, spinnerText, warningMark } from '../utils/display';\nimport { git } from '../utils/git';\n\n/** Package.json structure */\ninterface PackageJson {\n name?: string;\n version?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n engines?: Record<string, string>;\n packageManager?: string;\n overrides?: Record<string, string>;\n pnpm?: {\n overrides?: Record<string, string>;\n patchedDependencies?: Record<string, string>;\n packageExtensions?: Record<string, Record<string, unknown>>;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\ninterface ComparableVersion {\n major: number;\n minor: number;\n patch: number;\n}\n\nfunction parseComparableVersion(version: string): ComparableVersion | null {\n const trimmed = version.trim();\n\n if (\n trimmed === '' ||\n trimmed === '*' ||\n trimmed.includes('workspace:') ||\n trimmed.includes('catalog:') ||\n trimmed.includes('file:') ||\n trimmed.includes('link:') ||\n trimmed.includes('git+') ||\n trimmed.includes('github:') ||\n trimmed.includes('http://') ||\n trimmed.includes('https://') ||\n trimmed.includes('||')\n ) {\n return null;\n }\n\n const match = trimmed.match(\n /^(?:\\^|~|>=|<=|>|<|=)?\\s*v?(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/,\n );\n\n if (!match) return null;\n\n return {\n major: Number(match[1]),\n minor: Number(match[2] ?? 0),\n patch: Number(match[3] ?? 0),\n };\n}\n\nfunction compareVersions(left: ComparableVersion, right: ComparableVersion): number {\n if (left.major !== right.major) return left.major - right.major;\n if (left.minor !== right.minor) return left.minor - right.minor;\n return left.patch - right.patch;\n}\n\n/**\n * Check if upstream version is higher than fork version.\n * Returns true only if upstream is strictly higher — never downgrades.\n * For non-parseable values (workspace:*, etc.), returns false (keep fork's).\n */\nfunction isHigherVersion(upstreamVersion: string, forkVersion: string): boolean {\n if (upstreamVersion === forkVersion) return false;\n\n const upCoerced = parseComparableVersion(upstreamVersion);\n const forkCoerced = parseComparableVersion(forkVersion);\n\n if (!upCoerced || !forkCoerced) return false;\n\n return compareVersions(upCoerced, forkCoerced) > 0;\n}\n\n/**\n * Safe merge for Record<string, string> — add new entries, bump versions, never remove or downgrade.\n * With `addOnly` (e.g. scripts), existing fork entries are never overwritten.\n * Returns the merged record sorted alphabetically, plus the keys that were newly added.\n */\nfunction safeMergeRecord(\n forkRecord: Record<string, string> | undefined,\n upstreamRecord: Record<string, string> | undefined,\n addOnly = false,\n): { merged: Record<string, string>; changed: boolean; added: string[] } | undefined {\n if (!upstreamRecord) return undefined;\n\n const merged = { ...(forkRecord || {}) };\n const added: string[] = [];\n let changed = false;\n\n for (const [name, upstreamValue] of Object.entries(upstreamRecord)) {\n const forkValue = merged[name];\n\n if (forkValue === undefined) {\n // New entry from upstream — add it\n merged[name] = upstreamValue;\n added.push(name);\n changed = true;\n } else if (!addOnly && forkValue !== upstreamValue && isHigherVersion(upstreamValue, forkValue)) {\n // Upstream has a higher version — bump (preserve upstream's range prefix)\n merged[name] = upstreamValue;\n changed = true;\n }\n // Otherwise: fork has equal or higher version, or non-parseable — keep fork's\n }\n\n // Sort alphabetically\n const sorted = Object.fromEntries(Object.entries(merged).sort(([a], [b]) => a.localeCompare(b)));\n return { merged: sorted, changed, added };\n}\n\n/**\n * Safe merge for the `pnpm` key — recurse into sub-objects with add/bump-only logic.\n */\nfunction safeMergePnpm(\n forkPnpm: PackageJson['pnpm'],\n upstreamPnpm: PackageJson['pnpm'],\n): { merged: PackageJson['pnpm']; changed: boolean } | undefined {\n if (!upstreamPnpm) return undefined;\n\n const merged: NonNullable<PackageJson['pnpm']> = { ...(forkPnpm || {}) };\n let changed = false;\n\n // pnpm.overrides — same as dependency overrides: add new, bump versions\n if (upstreamPnpm.overrides) {\n const result = safeMergeRecord(\n merged.overrides as Record<string, string> | undefined,\n upstreamPnpm.overrides as Record<string, string>,\n );\n if (result?.changed) {\n merged.overrides = result.merged;\n changed = true;\n }\n }\n\n // pnpm.patchedDependencies — add-only (version comparison doesn't apply to patch paths)\n if (upstreamPnpm.patchedDependencies) {\n const forkPatched = (merged.patchedDependencies || {}) as Record<string, string>;\n const upstreamPatched = upstreamPnpm.patchedDependencies as Record<string, string>;\n\n for (const [name, value] of Object.entries(upstreamPatched)) {\n if (!(name in forkPatched)) {\n forkPatched[name] = value;\n changed = true;\n }\n }\n\n if (changed || !merged.patchedDependencies) {\n merged.patchedDependencies = Object.fromEntries(\n Object.entries(forkPatched).sort(([a], [b]) => a.localeCompare(b)),\n );\n }\n }\n\n // pnpm.packageExtensions — add new packages and add new sub-keys, never remove\n if (upstreamPnpm.packageExtensions) {\n const forkExts = (merged.packageExtensions || {}) as Record<string, Record<string, unknown>>;\n const upstreamExts = upstreamPnpm.packageExtensions as Record<string, Record<string, unknown>>;\n\n for (const [pkg, upstreamExt] of Object.entries(upstreamExts)) {\n if (!(pkg in forkExts)) {\n // New package extension — add entirely\n forkExts[pkg] = upstreamExt;\n changed = true;\n } else {\n // Existing package — add new sub-keys only\n for (const [subKey, subValue] of Object.entries(upstreamExt)) {\n if (!(subKey in forkExts[pkg])) {\n forkExts[pkg][subKey] = subValue;\n changed = true;\n }\n }\n }\n }\n\n merged.packageExtensions = forkExts;\n }\n\n // Other pnpm sub-keys — add if missing in fork\n for (const [key, value] of Object.entries(upstreamPnpm)) {\n if (['overrides', 'patchedDependencies', 'packageExtensions'].includes(key)) continue;\n if (!(key in merged)) {\n merged[key] = value;\n changed = true;\n }\n }\n\n return { merged, changed };\n}\n\n/**\n * Read a package.json file.\n */\nfunction readPackageJson(filePath: string): PackageJson | null {\n if (!existsSync(filePath)) return null;\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Write a package.json file (pretty-printed).\n */\nfunction writePackageJson(filePath: string, data: PackageJson): void {\n writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\\n`, 'utf-8');\n}\n\n/**\n * Get package.json from upstream ref.\n */\nasync function getUpstreamPackageJson(\n forkPath: string,\n upstreamRef: string,\n relativePath: string,\n): Promise<PackageJson | null> {\n const filePath = relativePath ? `${relativePath}/package.json` : 'package.json';\n\n try {\n return JSON.parse(await git(['show', `${upstreamRef}:${filePath}`], forkPath));\n } catch {\n return null;\n }\n}\n\n/**\n * Discover all package.json locations that exist in both fork and upstream.\n */\nasync function discoverPackageLocations(forkPath: string, upstreamRef: string): Promise<string[]> {\n // Get all package.json paths from upstream\n const stdout = await git(['ls-tree', '-r', '--name-only', upstreamRef], forkPath, { ignoreErrors: true });\n const upstreamPaths = stdout\n .split('\\n')\n .filter((p) => p.endsWith('/package.json') || p === 'package.json')\n .map((p) => (p === 'package.json' ? '' : p.replace('/package.json', '')));\n\n // Filter to locations that also exist in fork\n return upstreamPaths.filter((loc) => existsSync(join(forkPath, loc, 'package.json')));\n}\n\n/**\n * Sync a single package.json file with safe merge logic.\n */\nasync function syncPackageJson(\n forkPath: string,\n upstreamRef: string,\n relativePath: string,\n keysToSync: PackageJsonSyncKey[],\n): Promise<{ updated: boolean; changes: string[] }> {\n const changes: string[] = [];\n const pkgPath = join(forkPath, relativePath, 'package.json');\n\n const forkPkg = readPackageJson(pkgPath);\n const upstreamPkg = await getUpstreamPackageJson(forkPath, upstreamRef, relativePath);\n\n if (!forkPkg || !upstreamPkg) {\n return { updated: false, changes };\n }\n\n let updated = false;\n\n for (const key of keysToSync) {\n if (key === 'pnpm') {\n // Handle nested pnpm key\n const result = safeMergePnpm(forkPkg.pnpm, upstreamPkg.pnpm);\n if (result?.changed) {\n forkPkg.pnpm = result.merged;\n updated = true;\n changes.push('pnpm: merged');\n }\n continue;\n }\n\n if (key === 'packageManager') {\n // String key — only bump, never downgrade\n const upstreamValue = upstreamPkg[key] as string | undefined;\n const forkValue = forkPkg[key] as string | undefined;\n\n if (upstreamValue && !forkValue) {\n forkPkg[key] = upstreamValue;\n updated = true;\n changes.push(`${key}: added`);\n } else if (\n upstreamValue &&\n forkValue &&\n upstreamValue !== forkValue &&\n isHigherVersion(upstreamValue, forkValue)\n ) {\n forkPkg[key] = upstreamValue;\n updated = true;\n changes.push(`${key}: bumped`);\n }\n continue;\n }\n\n // All Record<string, string> keys — safe merge.\n // Scripts are add-only (never overwrite fork scripts); the rest also bump versions.\n const forkValue = forkPkg[key] as Record<string, string> | undefined;\n const upstreamValue = upstreamPkg[key] as Record<string, string> | undefined;\n\n const addOnly = key === 'scripts';\n const result = safeMergeRecord(forkValue, upstreamValue, addOnly);\n if (result?.changed) {\n (forkPkg as Record<string, unknown>)[key] = result.merged;\n updated = true;\n if (addOnly) {\n changes.push(...result.added.map((name) => `scripts.${name}: added`));\n } else {\n changes.push(`${key}: merged`);\n }\n }\n }\n\n if (updated) {\n writePackageJson(pkgPath, forkPkg);\n }\n\n return { updated, changes };\n}\n\n/**\n * Run the packages sync service.\n *\n * Dynamically discovers all package.json locations in both fork and upstream,\n * then syncs configured keys using safe merge logic (add-only, bump-only).\n *\n * When `conflictedFiles` is provided (e.g. after a sync that left conflicts),\n * any package.json that is itself unmerged is skipped to avoid clobbering\n * conflict markers; all other package.json files are still synced.\n */\nexport async function runPackages(config: RuntimeConfig, options: { conflictedFiles?: string[] } = {}): Promise<void> {\n createSpinner('syncing package.json files...');\n\n const keysToSync = config.settings.packageJsonSync || ['dependencies', 'devDependencies'];\n const conflictedSet = new Set(options.conflictedFiles ?? []);\n\n // Dynamically discover package locations\n const locations = await discoverPackageLocations(config.forkPath, config.upstreamRef);\n let changedCount = 0;\n const skipped: string[] = [];\n\n for (const location of locations) {\n const pkgRelPath = location ? `${location}/package.json` : 'package.json';\n\n // Skip package.json files that are themselves conflicted from the merge —\n // writing to them would clobber the conflict markers the user must resolve.\n if (conflictedSet.has(pkgRelPath)) {\n skipped.push(pkgRelPath);\n continue;\n }\n\n spinnerText(`syncing ${location || 'root'}/package.json...`);\n\n const { updated } = await syncPackageJson(config.forkPath, config.upstreamRef, location, keysToSync);\n\n if (updated) {\n changedCount += 1;\n }\n }\n\n spinnerSuccess(\n 'package sync complete',\n `${changedCount} package.json${changedCount === 1 ? ' was' : 's were'} changed`,\n );\n\n // Report any package.json files deferred due to merge conflicts\n if (skipped.length > 0) {\n console.info();\n console.warn(\n `${warningMark} skipped ${skipped.length} conflicted package.json file(s) — resolve the conflicts, commit the merge, then rerun \\`pnpm cella sync\\`:`,\n );\n for (const path of skipped) {\n console.warn(` ${pc.dim('→')} ${path}`);\n }\n }\n}\n","/**\n * Stats service for cella CLI.\n *\n * Counts files in the codebase using `git ls-files` (fast, respects .gitignore).\n * Categorizes by type and workspace package.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport pc from '../utils/colors';\nimport { printCoverageSummary } from '../utils/coverage-utils';\nimport { createSpinner, DIVIDER, spinnerSuccess } from '../utils/display';\nimport { git } from '../utils/git';\nimport { parseYamlBlockList } from '../utils/yaml';\n\n/** Extensions Biome can check (source code, config, styles) */\nconst sourceExtensions = new Set(['ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'json', 'jsonc', 'css', 'html']);\n\n/** File category for classification */\ntype FileCategory = 'test' | 'generated' | 'json' | 'other';\n\n/** Stats result for display or JSON output */\ninterface StatsResult {\n total: number;\n totalLoc: number;\n skipped: number;\n categories: Record<FileCategory, { files: number; loc: number }>;\n packages: Record<\n string,\n { total: number; loc: number; categories: Record<FileCategory, { files: number; loc: number }> }\n >;\n}\n\n/** Workspace package definition from pnpm-workspace.yaml */\ninterface WorkspacePackage {\n /** Display name (e.g., 'backend', 'cli/cella') */\n name: string;\n /** Path prefix to match (e.g., 'backend/', 'cli/cella/') */\n prefix: string;\n}\n\n/**\n * Parse pnpm-workspace.yaml to extract package paths.\n */\nasync function getWorkspacePackages(forkPath: string): Promise<WorkspacePackage[]> {\n const content = await readFile(join(forkPath, 'pnpm-workspace.yaml'), 'utf-8');\n\n return parseYamlBlockList(content, 'packages').map((pattern) => {\n // Handle wildcard patterns like 'cli/*' — resolved per file when matching\n if (pattern.endsWith('/*')) {\n const base = pattern.slice(0, -2);\n return { name: `${base}/*`, prefix: `${base}/` };\n }\n return { name: pattern, prefix: `${pattern}/` };\n });\n}\n\n/**\n * Classify a file path into a category.\n */\nfunction classifyFile(filePath: string): FileCategory {\n // Test files\n if (\n filePath.includes('.test.') ||\n filePath.includes('.spec.') ||\n filePath.includes('/tests/') ||\n filePath.includes('/test/') ||\n filePath.startsWith('tests/') ||\n filePath.includes('/__tests__/')\n ) {\n return 'test';\n }\n\n // Generated files\n if (\n filePath.includes('.gen.') ||\n filePath.includes('.gen/') ||\n filePath.includes('/gen/') ||\n filePath.startsWith('drizzle/') ||\n filePath.includes('/drizzle/') ||\n filePath.endsWith('.d.ts') ||\n filePath.includes('.tsbuildinfo')\n ) {\n return 'generated';\n }\n\n // JSON\n if (filePath.endsWith('.json') || filePath.endsWith('.jsonc')) {\n return 'json';\n }\n\n return 'other';\n}\n\n/**\n * Match a file to its workspace package, handling wildcard patterns.\n */\nfunction matchPackage(filePath: string, packages: WorkspacePackage[]): string {\n for (const pkg of packages) {\n if (pkg.name.endsWith('/*')) {\n // Wildcard: match any subfolder under the base prefix\n if (filePath.startsWith(pkg.prefix)) {\n // Extract the actual subpackage name (e.g., 'cli/cella' from 'cli/cella/src/foo.ts')\n const rest = filePath.slice(pkg.prefix.length);\n const subDir = rest.split('/')[0];\n if (subDir) {\n return `${pkg.prefix}${subDir}`;\n }\n }\n } else if (filePath.startsWith(pkg.prefix)) {\n return pkg.name;\n }\n }\n return '(root)';\n}\n\n/** Pathspec patterns for source extensions */\nconst sourcePathspecs = [...sourceExtensions].map((ext) => `*.${ext}`);\n\n/**\n * Collect file stats from the repository.\n * Uses `git grep -c ''` to get file list + line counts in a single call.\n */\nasync function collectStats(forkPath: string): Promise<StatsResult> {\n // Get all tracked source files with line counts (respects .gitignore, ~15ms)\n const output = await git(['grep', '-c', '', '--', ...sourcePathspecs], forkPath, { ignoreErrors: true });\n const allFilesOutput = await git(['ls-files', '--cached'], forkPath);\n const allFilesCount = allFilesOutput.split('\\n').filter(Boolean).length;\n\n const packages = await getWorkspacePackages(forkPath);\n\n // Parse \"path:count\" lines\n const entries: { path: string; loc: number }[] = [];\n for (const line of output.split('\\n')) {\n if (!line) continue;\n const sep = line.lastIndexOf(':');\n if (sep === -1) continue;\n entries.push({ path: line.slice(0, sep), loc: Number.parseInt(line.slice(sep + 1), 10) });\n }\n\n const skipped = allFilesCount - entries.length;\n const emptyCat = () => ({\n test: { files: 0, loc: 0 },\n generated: { files: 0, loc: 0 },\n json: { files: 0, loc: 0 },\n other: { files: 0, loc: 0 },\n });\n const categories = emptyCat();\n const pkgStats = new Map<\n string,\n { total: number; loc: number; categories: Record<FileCategory, { files: number; loc: number }> }\n >();\n let totalLoc = 0;\n\n for (const { path, loc } of entries) {\n const category = classifyFile(path);\n categories[category].files++;\n categories[category].loc += loc;\n totalLoc += loc;\n\n const pkg = matchPackage(path, packages);\n let entry = pkgStats.get(pkg);\n if (!entry) {\n entry = { total: 0, loc: 0, categories: emptyCat() };\n pkgStats.set(pkg, entry);\n }\n entry.total++;\n entry.loc += loc;\n entry.categories[category].files++;\n entry.categories[category].loc += loc;\n }\n\n // Sort packages by source LOC descending\n const sortedPackages = Object.fromEntries(\n [...pkgStats.entries()].sort((a, b) => b[1].categories.other.loc - a[1].categories.other.loc),\n );\n\n return { total: entries.length, totalLoc, skipped, categories, packages: sortedPackages };\n}\n\n/**\n * Format a number with padding for table alignment.\n */\nfunction pad(n: number, width = 6): string {\n return String(n).padStart(width);\n}\n\n/**\n * Format a number with K suffix for large values.\n */\nfunction formatLoc(n: number): string {\n if (n >= 1000) return `${(n / 1000).toFixed(1)}k`;\n return String(n);\n}\n\n/**\n * Format a LOC value for fixed-width table columns.\n */\nfunction formatLocColumn(n: number, width = 8): string {\n return formatLoc(n).padStart(width);\n}\n\n/**\n * Format a percentage with fixed width (e.g., '05.0%', '89.7%').\n */\nfunction fmtPct(value: number, total: number): string {\n const pct = ((value / total) * 100).toFixed(1);\n return `${pct.padStart(5)}%`;\n}\n\n/**\n * Print stats in table format.\n */\nfunction printStats(stats: StatsResult, verbose: boolean): void {\n console.info();\n console.info(\n ` ${pc.bold('source files')} ${String(stats.total)} ${pc.dim(`(${stats.skipped} non-source skipped)`)}`,\n );\n console.info(` ${pc.bold('lines of code')} ${pc.cyan(formatLoc(stats.totalLoc))}`);\n console.info();\n\n const catEntries: [string, { files: number; loc: number }][] = [\n ['source & config', stats.categories.other],\n ['test', stats.categories.test],\n ['generated', stats.categories.generated],\n ['json', stats.categories.json],\n ];\n for (const [label, data] of catEntries) {\n console.info(\n ` ${pad(data.files)} ${pc.dim(fmtPct(data.files, stats.total))} ${label.padEnd(18)} ${pc.cyan(formatLocColumn(data.loc))} ${pc.dim(fmtPct(data.loc, stats.totalLoc))}`,\n );\n }\n\n console.info();\n console.info(DIVIDER);\n console.info();\n\n if (verbose) {\n // Verbose: show per-package category breakdown\n const header = ` ${''.padEnd(6)} ${'package'.padEnd(18)} ${'loc'.padStart(8)} ${'test'.padStart(6)} ${'gen'.padStart(6)} ${'json'.padStart(6)} ${'src'.padStart(6)}`;\n console.info(pc.dim(header));\n for (const [name, data] of Object.entries(stats.packages)) {\n const c = data.categories;\n const srcFiles = c.other.files;\n const srcLoc = c.other.loc;\n if (srcFiles === 0) continue;\n console.info(\n ` ${pc.dim(pad(srcFiles))} ${name.padEnd(18)} ${pc.cyan(formatLocColumn(srcLoc))} ${pc.dim(pad(c.test.files))} ${pc.dim(pad(c.generated.files))} ${pc.dim(pad(c.json.files))} ${pc.dim(pad(srcFiles))}`,\n );\n }\n } else {\n for (const [name, data] of Object.entries(stats.packages)) {\n const srcFiles = data.categories.other.files;\n const srcLoc = data.categories.other.loc;\n if (srcFiles === 0) continue;\n console.info(\n ` ${pad(srcFiles)} ${pc.dim(fmtPct(srcFiles, stats.categories.other.files))} ${name.padEnd(18)} ${pc.cyan(formatLocColumn(srcLoc))} ${pc.dim(fmtPct(srcLoc, stats.categories.other.loc))}`,\n );\n }\n }\n\n console.info();\n}\n\n/**\n * Run the stats service.\n */\nexport async function runStats(\n forkPath: string,\n options: { json?: boolean; verbose?: boolean; refreshCoverage?: boolean } = {},\n): Promise<void> {\n createSpinner('counting files...');\n const stats = await collectStats(forkPath);\n spinnerSuccess('Finished counting by raw line of code');\n\n if (options.json) {\n console.info(JSON.stringify(stats, null, 2));\n } else {\n printStats(stats, options.verbose ?? false);\n console.info();\n printCoverageSummary(forkPath, { refresh: options.refreshCoverage });\n }\n}\n","/**\n * Coverage utilities for the Cella CLI stats service.\n *\n * Reads the cached `.coverage/coverage-summary.json` produced by the\n * `json-summary` Vitest reporter (see root vitest.config.ts) and renders a\n * compact overview. The stats service normally only reads\n * the artifact from the last default `pnpm test` run, warning when it is stale\n * or missing. Passing `--coverage` refreshes it first.\n */\n\nimport { spawnSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport pc from './colors';\n\n/** A single metric block from a coverage-summary.json entry. */\ninterface CoverageMetric {\n total: number;\n covered: number;\n skipped: number;\n pct: number;\n}\n\n/** One file (or the `total`) entry in coverage-summary.json. */\ninterface CoverageEntry {\n lines: CoverageMetric;\n statements: CoverageMetric;\n functions: CoverageMetric;\n branches: CoverageMetric;\n}\n\n/** Shape of Vitest's coverage-summary.json. Keys are absolute file paths plus `total`. */\ntype CoverageSummary = Record<string, CoverageEntry> & { total: CoverageEntry };\n\n/** Coverage data is considered stale after this many ms (7 days). */\nconst STALE_THRESHOLD_MS = 7 * 24 * 60 * 60 * 1000;\n\n/** Path to the cached summary written by the `json-summary` reporter. */\nfunction summaryPath(forkPath: string): string {\n return path.join(forkPath, '.coverage', 'coverage-summary.json');\n}\n\n/** Color a percentage: green ≥ 80, yellow ≥ 50, red below. */\nfunction colorPct(pct: number): string {\n const label = `${pct.toFixed(2)}%`;\n if (pct >= 80) return pc.green(label);\n if (pct >= 50) return pc.yellow(label);\n return pc.red(label);\n}\n\n/** Human-friendly \"x days/hours ago\" from a timestamp. */\nfunction formatAge(ms: number): string {\n const days = Math.floor(ms / (24 * 60 * 60 * 1000));\n if (days >= 1) return `${days} day${days === 1 ? '' : 's'} ago`;\n const hours = Math.floor(ms / (60 * 60 * 1000));\n if (hours >= 1) return `${hours} hour${hours === 1 ? '' : 's'} ago`;\n const mins = Math.floor(ms / (60 * 1000));\n return `${mins} minute${mins === 1 ? '' : 's'} ago`;\n}\n\n/**\n * Re-run the full coverage suite via `pnpm test`. Output is streamed so the\n * user sees progress (Docker boot, test run, etc.). Returns true on success.\n */\nexport function refreshCoverage(forkPath: string): boolean {\n console.info(pc.dim('running `pnpm test` (this spins up Docker and runs the full suite)...'));\n const result = spawnSync('pnpm', ['test'], { cwd: forkPath, stdio: 'inherit' });\n return result.status === 0;\n}\n\n/**\n * Print a compact coverage overview from the cached summary file.\n *\n * @param forkPath - Repository root.\n * @param options.refresh - When true, run `pnpm test` first to regenerate\n * the cache before rendering.\n */\nexport function printCoverageSummary(forkPath: string, options: { refresh?: boolean } = {}): void {\n const file = summaryPath(forkPath);\n\n if (options.refresh) {\n const ok = refreshCoverage(forkPath);\n if (!ok) {\n console.info(pc.red('coverage run failed — showing last cached results (if any)'));\n }\n console.info();\n }\n\n if (!fs.existsSync(file)) {\n console.info(pc.bold('coverage'));\n console.info(pc.yellow(' no coverage data found — run `pnpm test` to generate it'));\n console.info();\n return;\n }\n\n let summary: CoverageSummary;\n let mtimeMs: number;\n try {\n summary = JSON.parse(fs.readFileSync(file, 'utf-8')) as CoverageSummary;\n mtimeMs = fs.statSync(file).mtimeMs;\n } catch {\n console.info(pc.bold('coverage'));\n console.info(pc.yellow(' could not read coverage-summary.json — run `pnpm test` to regenerate'));\n console.info();\n return;\n }\n\n const ageMs = Date.now() - mtimeMs;\n const stale = ageMs > STALE_THRESHOLD_MS;\n\n // Roll up per-package line coverage by the first path segment relative to root.\n const perPackage = new Map<string, { covered: number; total: number }>();\n for (const [key, entry] of Object.entries(summary)) {\n if (key === 'total') continue;\n const rel = path.relative(forkPath, key);\n if (rel.startsWith('..')) continue;\n const pkg = rel.split(path.sep)[0];\n const acc = perPackage.get(pkg) ?? { covered: 0, total: 0 };\n acc.covered += entry.lines.covered;\n acc.total += entry.lines.total;\n perPackage.set(pkg, acc);\n }\n\n // Header with freshness indicator.\n const ageLabel = formatAge(ageMs);\n console.info(pc.bold('coverage'), pc.dim(`(updated ${ageLabel})`));\n if (stale) {\n console.info(pc.yellow(' ⚠ data is older than 7 days — run `pnpm test` to refresh'));\n }\n\n // Overall totals.\n const total = summary.total;\n console.info(\n ` ${pc.bold('overall')} ` +\n `lines ${colorPct(total.lines.pct)} ${pc.dim(`(${total.lines.covered}/${total.lines.total})`)} ` +\n `funcs ${colorPct(total.functions.pct)} ` +\n `branches ${colorPct(total.branches.pct)}`,\n );\n\n // Per-package line coverage, worst first.\n const rows = [...perPackage.entries()]\n .map(([pkg, v]) => ({ pkg, pct: v.total ? (100 * v.covered) / v.total : 0, ...v }))\n .sort((a, b) => a.pct - b.pct);\n\n const nameWidth = Math.max(...rows.map((r) => r.pkg.length), 0);\n for (const r of rows) {\n console.info(` ${r.pkg.padEnd(nameWidth)} ${colorPct(r.pct)} ${pc.dim(`(${r.covered}/${r.total})`)}`);\n }\n console.info();\n}\n"],"mappings":"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","names":["existsSync","statSync","join","resolve","process","join","process","process","process","process","existsSync","join","z","pad","join","existsSync","z","join","resolve","process","process","resolve","join","existsSync","join","existsSync","join","join","process","basename","writeFileSync","basename","join","process","existsSync","tmpdir","basename","join","process","existsSync","join","join","path","join","existsSync","fetch","join","existsSync","path","join","tmpdir","basename","existsSync","process","path","fetch","basename","fs","path","execFile","promisify","execFileAsync","promisify","execFile","readFileSync","join","select","dirname","join","path","dirname","join","unlinkSync","existsSync","resolve","resolve","existsSync","readFileSync","join","checkbox","path","fork","select","resolve","process","Separator","select","spawnSync","select","spawnSync","existsSync","readFileSync","writeFileSync","join","existsSync","readFileSync","writeFileSync","join","result","upstreamValue","forkValue","path","merge","spawnSync","select","resolve","Separator","select","process","readFile","join","spawnSync","fs","path","spawnSync","readFile","join","sep","path","resolve","existsSync","statSync","process","join"]}
1
+ {"version":3,"sources":["../src/cella-cli.ts","../src/cli.ts","../src/utils/colors.ts","../src/utils/env.ts","../src/utils/config.ts","../src/config/types.ts","../src/utils/managed-files.ts","../src/utils/module-territory.ts","../src/utils/display.ts","../package.json","../src/utils/overrides.ts","../src/services/analyze.ts","../src/utils/diff.ts","../src/utils/cleanup.ts","../src/utils/git.ts","../src/utils/manifest.ts","../src/services/analyze-core.ts","../src/services/merge-engine.ts","../src/services/audit.ts","../src/utils/audit-utils.ts","../src/utils/yaml.ts","../src/services/contributions.ts","../src/services/contrib-core.ts","../src/services/fork-utils.ts","../src/services/forks.ts","../src/services/sync.ts","../src/utils/gh.ts","../src/services/packages.ts","../src/services/stats.ts","../src/utils/coverage-utils.ts"],"sourcesContent":["#!/usr/bin/env tsx\n/**\n * Cella CLI v2 - Main entry point\n *\n * Worktree-based merge approach that isolates all merge operations\n * from the main repository until the final atomic rsync copy.\n */\n\nimport { existsSync, statSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport process from 'node:process';\nimport { parseCli } from './cli';\nimport type { CellaCliConfig } from './config/types';\nimport { runAnalyze } from './services/analyze';\nimport { runAudit } from './services/audit';\nimport { runContributions } from './services/contributions';\nimport { runForks } from './services/forks';\nimport { runStats } from './services/stats';\nimport { runSyncCommand } from './services/sync';\nimport { registerSignalHandlers } from './utils/cleanup';\nimport pc from './utils/colors';\nimport { loadConfig } from './utils/config';\nimport { getEnv } from './utils/env';\n\n/**\n * Determine the fork path.\n *\n * Priority:\n * 1. CELLA_FORK_PATH environment variable\n * 2. Current working directory (where the CLI is run from)\n *\n * Note: When run via pnpm filter, cwd may be cli/cella - we detect and navigate up.\n */\nfunction getForkPath(): string {\n const envPath = getEnv('CELLA_FORK_PATH');\n if (envPath) {\n const resolved = resolve(envPath);\n if (!existsSync(resolved) || !statSync(resolved).isDirectory()) {\n throw new Error(`CELLA_FORK_PATH is not a valid directory: ${resolved}`);\n }\n return resolved;\n }\n\n let cwd = process.cwd();\n\n // If running from within cli/cella (e.g., via pnpm --filter), go up to find the fork root\n if (cwd.endsWith('/cli/cella') || cwd.endsWith('\\\\cli\\\\cella')) {\n cwd = resolve(cwd, '../..');\n }\n\n return cwd;\n}\n\n/**\n * Pre-flight checks before running a service.\n *\n * The sync service cuts its own temporary branch from the trunk and owns its own clean/resume\n * state, so preflight no longer cares which branch you are on or whether the tree is clean — it\n * only verifies we are inside a git repository.\n */\nasync function preflight(forkPath: string): Promise<void> {\n if (!existsSync(join(forkPath, '.git'))) {\n throw new Error(`not a git repository: ${forkPath}`);\n }\n}\n\nfunction isHelpOrVersionRequest(): boolean {\n return (\n process.argv.slice(2).some((arg) => arg === '--help' || arg === '-h' || arg === '--version' || arg === '-v') ||\n process.argv[2] === 'help'\n );\n}\n\n/**\n * Main entry point.\n */\nasync function main(): Promise<void> {\n // Register signal handlers for cleanup\n registerSignalHandlers();\n\n try {\n // Determine fork path\n const forkPath = getForkPath();\n\n if (isHelpOrVersionRequest()) {\n await parseCli({ settings: { upstreamUrl: '', upstreamBranch: 'main' } } as CellaCliConfig, forkPath);\n return;\n }\n\n // Load config\n const userConfig = await loadConfig(forkPath);\n\n // Parse CLI and get runtime config\n const config = await parseCli(userConfig, forkPath);\n\n // Run preflight checks (except for services that operate on other fork paths)\n if (!['audit', 'forks', 'contributions', 'stats'].includes(config.service)) {\n await preflight(forkPath);\n }\n\n // Route to service\n switch (config.service) {\n case 'analyze': {\n await runAnalyze(config);\n break;\n }\n\n case 'sync': {\n await runSyncCommand(config);\n break;\n }\n\n case 'audit':\n await runAudit(config, { force: config.force, checkOverrides: config.checkOverrides });\n break;\n\n case 'forks':\n await runForks(config);\n break;\n\n case 'contributions':\n await runContributions(config);\n break;\n\n case 'stats':\n await runStats(config.forkPath, { verbose: config.verbose, refreshCoverage: config.coverage });\n break;\n }\n\n console.info();\n } catch (error) {\n console.error();\n console.error(`${pc.red('✗')} ${error instanceof Error ? error.message : 'unknown error'}`);\n process.exit(1);\n }\n}\n\nmain();\n","/**\n * CLI entry point for sync CLI v2.\n *\n * Parses command line arguments and routes to appropriate service.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport process from 'node:process';\nimport { select } from '@inquirer/prompts';\nimport { Command } from 'commander';\nimport type { AnalyzeScope, CellaCliConfig, RuntimeConfig, SyncService } from './config/types';\nimport pc from './utils/colors';\nimport { resolveUpstream } from './utils/config';\nimport { NAME, printHeader, setJsonMode, VERSION } from './utils/display';\nimport { printWarnings, validateOverrides } from './utils/overrides';\n\ntype CliServiceSelection = {\n service?: SyncService;\n options: CliOptionState;\n};\n\ntype CliOptionState = Pick<\n RuntimeConfig,\n | 'logFile'\n | 'verbose'\n | 'list'\n | 'json'\n | 'diff'\n | 'openDiff'\n | 'scope'\n | 'fork'\n | 'hard'\n | 'unpinned'\n | 'track'\n | 'force'\n | 'checkOverrides'\n | 'coverage'\n | 'directMerge'\n>;\n\ntype MenuContext = {\n hasForks: boolean;\n isUpstreamRepo: boolean;\n};\n\ntype ServiceOptionDefinition = {\n flags: string;\n description: string;\n};\n\ntype ServiceDefinition = {\n name: SyncService;\n description: string;\n options?: ServiceOptionDefinition[];\n includeInMenu?: (context: MenuContext) => boolean;\n menuDescription?: (context: MenuContext) => string;\n};\n\nfunction readOptions(opts: Record<string, unknown>): CliOptionState {\n const scope = typeof opts.scope === 'string' ? opts.scope : undefined;\n if (scope && scope !== 'all' && scope !== 'risk' && scope !== 'protected') {\n throw new Error(`invalid --scope '${scope}'. expected one of: all, risk, protected`);\n }\n const normalizedScope = scope as AnalyzeScope | undefined;\n\n return {\n logFile: opts.log === true,\n verbose: opts.verbose === true,\n list: opts.list === true,\n json: opts.json === true,\n diff: typeof opts.diff === 'string' ? opts.diff : undefined,\n openDiff: typeof opts.openDiff === 'string' ? opts.openDiff : undefined,\n scope: normalizedScope,\n fork: typeof opts.fork === 'string' ? opts.fork : undefined,\n hard: opts.hard === true,\n unpinned: opts.unpinned === true,\n track: opts.track === 'release' || opts.track === 'branch' ? opts.track : undefined,\n force: opts.force === true,\n checkOverrides: opts.checkOverrides === true,\n coverage: opts.coverage === true,\n directMerge: opts.directMerge === true,\n };\n}\n\nconst serviceDefinitions: ServiceDefinition[] = [\n {\n name: 'analyze',\n description: 'dry run to see what would change on sync',\n options: [\n { flags: '--log', description: 'write complete file list to cella-sync.log' },\n { flags: '--list', description: 'non-interactive output for tooling (one file per line)' },\n { flags: '--json', description: 'machine-readable output for tooling/agents' },\n { flags: '--scope <scope>', description: 'analyze scope for --list/--json: all|risk|protected' },\n { flags: '--track <mode>', description: 'override upstream tracking for this run: release|branch' },\n { flags: '--diff <path>', description: 'print unified diff for one file, then exit' },\n { flags: '--open-diff <path>', description: 'open a browser diff for one file, then exit' },\n ],\n includeInMenu: (context) => !context.isUpstreamRepo,\n },\n {\n name: 'sync',\n description: 'merge upstream changes into your app',\n options: [\n { flags: '--log', description: 'write complete file list to cella-sync.log' },\n { flags: '--hard', description: 'overwrite drifted files with upstream version (aggressive realignment)' },\n { flags: '--unpinned', description: 'ignore pinned files (except package.json) to resurface upstream changes' },\n { flags: '--track <mode>', description: 'override upstream tracking for this run: release|branch' },\n {\n flags: '--direct-merge',\n description: 'auto-merge (squash) the sync PR once checks pass — needs auto-merge enabled on the repo',\n },\n ],\n includeInMenu: (context) => !context.isUpstreamRepo,\n menuDescription: () => 'merge upstream changes + sync package.json',\n },\n {\n name: 'audit',\n description: 'check for outdated packages & vulnerabilities',\n options: [\n { flags: '--list', description: 'skip interactive update prompts after printing audit results' },\n { flags: '--force', description: 'bypass pnpm metadata cache for fresh registry data' },\n { flags: '--check-overrides', description: 'check which pnpm.overrides are still needed' },\n ],\n },\n {\n name: 'forks',\n description: 'sync downstream to local fork repositories',\n options: [\n { flags: '--fork <name>', description: 'pre-select fork by name (skips fork selection prompt)' },\n { flags: '--log', description: 'write complete file list to cella-sync.log for each synced fork' },\n { flags: '-V, --verbose', description: 'show detailed output during operations' },\n { flags: '--hard', description: 'overwrite drifted files with upstream version (aggressive realignment)' },\n ],\n includeInMenu: (context) => context.hasForks,\n },\n {\n name: 'contributions',\n description: 'pull and adopt changes from forks',\n options: [\n { flags: '--fork <name>', description: 'select a specific fork directly (skips fork selection)' },\n { flags: '--list', description: 'non-interactive output (one file per line)' },\n { flags: '--json', description: 'machine-readable JSON output for tooling/agents' },\n { flags: '--diff <path>', description: 'print the unified diff for a single contributed file, then exit' },\n ],\n includeInMenu: (context) => context.hasForks,\n },\n {\n name: 'stats',\n description: 'count files by category and workspace package',\n options: [\n { flags: '-V, --verbose', description: 'show detailed output during operations' },\n { flags: '--coverage', description: 'regenerate test coverage before showing the stats summary' },\n ],\n },\n];\n\nasync function getMenuContext(userConfig: CellaCliConfig, forkPath: string): Promise<MenuContext> {\n return {\n hasForks: (userConfig.forks?.length ?? 0) > 0,\n isUpstreamRepo: JSON.parse(readFileSync(join(forkPath, 'package.json'), 'utf8')).name === 'cella',\n };\n}\n\n/**\n * Build service menu choices, conditionally including optional services.\n */\nfunction buildServiceChoices(context: MenuContext) {\n // Pad service labels to align descriptions (longest label is 'contributions').\n const label = (name: string) => name.padEnd(14);\n const baseChoices = serviceDefinitions\n .filter((service) => service.includeInMenu?.(context) ?? true)\n .map((service) => ({\n value: service.name,\n name: `${label(service.name)}${pc.dim(service.menuDescription?.(context) ?? service.description)}`,\n }));\n\n return [\n ...baseChoices,\n { type: 'separator' as const, separator: '─'.repeat(40) },\n { value: 'exit' as const, name: pc.red(`${label('exit')}${pc.dim('quit without doing anything')}`) },\n ];\n}\n\nfunction addServiceCommand(\n program: Command,\n definition: ServiceDefinition,\n setSelection: (selection: CliServiceSelection) => void,\n) {\n const command = program.command(definition.name).description(definition.description);\n\n for (const option of definition.options ?? []) {\n command.option(option.flags, option.description);\n }\n\n command.action((opts) => {\n setSelection({\n service: definition.name,\n options: readOptions(opts),\n });\n });\n}\n\nfunction buildProgram(setSelection: (selection: CliServiceSelection) => void): Command {\n const program = new Command(NAME)\n .name('cella')\n .version(VERSION, '-v, --version', 'output the current version')\n .usage('[service] [options]')\n .helpOption('-h, --help', 'display help for a command')\n .showHelpAfterError()\n .addHelpText(\n 'after',\n [\n '',\n 'Examples:',\n ' $ cella analyze',\n ' $ cella analyze --json --scope risk',\n ' $ cella analyze --open-diff frontend/src/routes/index.tsx',\n ' $ cella sync --hard',\n ' $ cella sync --unpinned',\n ' $ cella sync --track branch',\n ' $ cella sync --direct-merge',\n ' $ cella audit --check-overrides',\n ' $ cella contributions --fork raak --json',\n ].join('\\n'),\n );\n\n for (const definition of serviceDefinitions) {\n addServiceCommand(program, definition, setSelection);\n }\n\n return program;\n}\n\nfunction parseCommandLine(argv: string[]): CliServiceSelection {\n if (argv.length <= 2) {\n return { options: readOptions({}) };\n }\n\n let selection: CliServiceSelection = { options: readOptions({}) };\n const program = buildProgram((nextSelection) => {\n selection = nextSelection;\n });\n\n program.parse(argv);\n return selection;\n}\n\nasync function promptForService(userConfig: CellaCliConfig, forkPath: string): Promise<SyncService> {\n const selected = await select<SyncService | 'exit'>({\n message: 'choose a service:',\n choices: buildServiceChoices(await getMenuContext(userConfig, forkPath)),\n loop: false,\n });\n\n if (selected === 'exit') {\n console.info(pc.dim('exiting...'));\n console.info();\n process.exit(0);\n }\n\n console.info();\n return selected;\n}\n\nfunction buildRuntimeConfig(\n userConfig: CellaCliConfig,\n forkPath: string,\n selection: CliServiceSelection,\n): RuntimeConfig {\n // Static fallback ref (branch tip). For release tracking the merge engine resolves\n // the concrete release-tag ref after fetching and writes it back to config.upstreamRef.\n const { branchRef } = resolveUpstream(userConfig.settings);\n\n return {\n ...userConfig,\n forkPath,\n upstreamRef: branchRef,\n service: selection.service ?? 'analyze',\n ...selection.options,\n };\n}\n\n/**\n * Parse CLI arguments and return configuration.\n */\nexport async function parseCli(userConfig: CellaCliConfig, forkPath: string): Promise<RuntimeConfig> {\n const selection = parseCommandLine(process.argv);\n\n // In machine-output modes (--json, --diff), reserve stdout for the payload/patch\n // and route all human output (header, warnings, spinner) to stderr.\n if (selection.options.json || selection.options.diff) setJsonMode(true);\n\n // Print header\n printHeader();\n\n // Validate config and show warnings\n const warnings = validateOverrides(userConfig, forkPath);\n if (warnings.length > 0) {\n printWarnings(warnings);\n console.info();\n }\n\n // If no service provided, prompt for it\n if (!selection.service) {\n selection.service = await promptForService(userConfig, forkPath);\n }\n\n return buildRuntimeConfig(userConfig, forkPath, selection);\n}\n","import process from 'node:process';\nimport { styleText } from 'node:util';\nimport { hasEnv } from './env';\n\ntype ColorStyle = 'blue' | 'bold' | 'cyan' | 'dim' | 'gray' | 'green' | 'magenta' | 'red' | 'white' | 'yellow';\n\nfunction colorsEnabled(): boolean {\n if (hasEnv('NO_COLOR')) return false;\n if (hasEnv('FORCE_COLOR')) return true;\n return !!process.stdout.isTTY;\n}\n\nfunction applyStyle(style: ColorStyle, text: string): string {\n if (!colorsEnabled()) return text;\n return styleText(style, text, { validateStream: false });\n}\n\nconst pc = {\n blue: (text: string) => applyStyle('blue', text),\n bold: (text: string) => applyStyle('bold', text),\n cyan: (text: string) => applyStyle('cyan', text),\n dim: (text: string) => applyStyle('dim', text),\n gray: (text: string) => applyStyle('gray', text),\n green: (text: string) => applyStyle('green', text),\n magenta: (text: string) => applyStyle('magenta', text),\n red: (text: string) => applyStyle('red', text),\n white: (text: string) => applyStyle('white', text),\n yellow: (text: string) => applyStyle('yellow', text),\n};\n\nexport default pc;\n","import process from 'node:process';\n\n/**\n * Centralized environment access for CLI/runtime integration points.\n */\nexport function getEnv(name: string): string | undefined {\n // biome-ignore lint/style/noProcessEnv: This module centralizes intentional CLI environment access.\n return process.env[name];\n}\n\nexport function hasEnv(name: string): boolean {\n // biome-ignore lint/style/noProcessEnv: This module centralizes intentional CLI environment access.\n return name in process.env;\n}\n\nexport function getEnvSnapshot(): NodeJS.ProcessEnv {\n // biome-ignore lint/style/noProcessEnv: This module centralizes intentional CLI environment access.\n return { ...process.env };\n}\n","/**\n * Config loading utilities for sync CLI.\n *\n * Shared between main entry point and forks service.\n */\n\nimport { existsSync, realpathSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { z } from 'zod';\nimport { type CellaCliConfig, cellaConfigSchema, type SyncSettings } from '../config/types';\nimport { CONFIG_FILE } from './managed-files';\nimport { resolveAppModuleFolders } from './module-territory';\n\n/** Default git remote name used to point at the upstream repository. */\nexport const DEFAULT_UPSTREAM_REMOTE = 'cella-upstream';\n\n/** Default branch used when a config omits `upstreamBranch`; also cella's fork-compare base. */\nexport const DEFAULT_BRANCH = 'main';\n\n/**\n * Prefix for the temporary integration branches that `cella sync` cuts per run\n * (e.g. `cella/sync/20260702-1430`).\n *\n * The three-segment shape (`cella/sync/<stamp>`) means it can never collide with a real branch\n * named `cella` or `cella/sync`.\n */\nexport const DEFAULT_SYNC_PREFIX = 'cella/sync';\n\n/**\n * Default trunk branch that `cella sync` cuts from and opens PRs into.\n */\nexport const DEFAULT_RELEASE_BASE = 'main';\n\n/**\n * Whether `branch` is one of the temporary integration branches `cella sync` cuts, i.e. it\n * lives under the internal `cella/sync/` namespace.\n */\nexport function isTemporarySyncBranch(branch: string): boolean {\n return branch.startsWith(`${DEFAULT_SYNC_PREFIX}/`);\n}\n\n/**\n * Resolve the trunk branch `cella sync` cuts the temporary branch from and PRs into.\n */\nexport function resolveReleaseBase(settings: SyncSettings): string {\n return settings.releaseBase ?? DEFAULT_RELEASE_BASE;\n}\n\n/**\n * Build a unique temporary integration branch name for a sync cycle, e.g.\n * `cella/sync/20260702-1430`. Cutting a fresh branch per cycle keeps each PR\n * scoped to that sync's upstream delta.\n */\nexport function buildTemporarySyncBranch(): string {\n const now = new Date();\n const pad = (n: number) => String(n).padStart(2, '0');\n const stamp = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}`;\n return `${DEFAULT_SYNC_PREFIX}/${stamp}`;\n}\n\n/**\n * Resolve the upstream tracking plan from sync settings.\n *\n * Single source of truth shared by the CLI entry point and the merge engine.\n * The concrete ref for release tracking (latest tag) can only be resolved after\n * fetching, so this returns a plan; the merge engine turns it into a ref.\n *\n * - `track`: 'release' (default) syncs to the latest release tag; 'branch' follows the tip.\n * - `branchRef`: `<DEFAULT_UPSTREAM_REMOTE>/<branch>` — the branch-track ref and static fallback.\n */\nexport function resolveUpstream(settings: SyncSettings): {\n track: 'release' | 'branch';\n branchRef: string;\n} {\n const track = settings.upstreamTrack ?? 'release';\n const branch = settings.upstreamBranch ?? DEFAULT_BRANCH;\n const branchRef = `${DEFAULT_UPSTREAM_REMOTE}/${branch}`;\n return { track, branchRef };\n}\n\n/**\n * Load cella/cella.config.ts from a fork/repo path.\n */\nexport async function loadConfig(forkPath: string): Promise<CellaCliConfig> {\n const configPath = join(forkPath, CONFIG_FILE);\n\n if (!existsSync(configPath)) {\n throw new Error(`config file not found: ${configPath}`);\n }\n\n // Resolve symlinks and validate path stays within fork directory\n const realConfigPath = realpathSync(configPath);\n const realForkPath = realpathSync(resolve(forkPath));\n if (!realConfigPath.startsWith(`${realForkPath}/`)) {\n throw new Error('config path resolves outside fork directory');\n }\n\n let configModule: { default?: unknown };\n try {\n configModule = await import(realConfigPath);\n } catch (error) {\n // Syntax/runtime errors while evaluating the config must fail closed: a config that\n // cannot be loaded means sync protections (ignored/pinned) are unknown.\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`failed to load ${configPath}: ${message}`);\n }\n\n // Strict schema validation.\n const result = cellaConfigSchema.safeParse(configModule.default);\n if (!result.success) {\n throw new Error(`invalid ${configPath}:\\n${z.prettifyError(result.error)}`);\n }\n const config: CellaCliConfig = result.data;\n\n // Auto-derive fork-owned module folders (modules declaring `owner: 'app'`) and merge\n // them into ignored. This keeps app modules as fork territory: upstream never\n // adds/modifies/deletes them during sync, and the contributions service never offers\n // them back upstream. Derived entries always exist (they come from real files), so\n // config validation never warns about them.\n const appModuleFolders = resolveAppModuleFolders(realForkPath);\n if (appModuleFolders.length > 0) {\n const existing = config.overrides?.ignored ?? [];\n config.overrides = {\n ...config.overrides,\n ignored: [...new Set([...existing, ...appModuleFolders])],\n };\n }\n\n return config;\n}\n","/**\n * Sync CLI v2 - Configuration Types\n *\n * Simplified configuration for worktree-based merge approach.\n */\n\nimport { z } from 'zod';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// PUBLIC API - for cella/cella.config.ts\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Valid package.json keys that can be synced */\nexport type PackageJsonSyncKey =\n | 'dependencies'\n | 'devDependencies'\n | 'peerDependencies'\n | 'optionalDependencies'\n | 'scripts'\n | 'engines'\n | 'packageManager'\n | 'overrides'\n | 'pnpm';\n\n/**\n * Sync settings - all configurable options for the sync CLI.\n * Hover over each property for documentation.\n */\nexport interface SyncSettings {\n /** Upstream repository URL (e.g., 'git@github.com:cellajs/cella.git') */\n upstreamUrl: string;\n\n /**\n * Upstream branch, used for `upstreamTrack: 'branch'` and for GitHub file links.\n * Defaults to 'main'.\n */\n upstreamBranch?: string;\n\n /**\n * How to track upstream cella. Defaults to 'release'.\n * - 'release' (default): sync to a published cella release tag (`v*`). Stable and\n * reviewable — each bump maps to a changelog. Uses the latest release.\n * - 'branch': follow the bleeding-edge tip of `upstreamBranch`. For cella\n * maintainers and forks doing active development on top of unreleased changes.\n */\n upstreamTrack?: 'release' | 'branch';\n\n /**\n * Trunk branch that `pnpm cella sync` cuts the temporary branch from and that you open the\n * squash-merge PR into. Defaults to 'main'. Cutting fresh from trunk each cycle keeps every\n * PR limited to that cycle's upstream delta (no accumulation) and `main` linear.\n */\n releaseBase?: string;\n\n /** Which package.json keys to sync (default: ['dependencies', 'devDependencies']) */\n packageJsonSync?: PackageJsonSyncKey[];\n\n /**\n * Automatically run packages sync after the sync service completes.\n * When true (default), the packages service is hidden from the menu\n * and runs automatically as part of sync.\n * Set to false to keep packages as a separate manual service.\n */\n syncWithPackages?: boolean;\n\n /**\n * How to link files in CLI output.\n * - 'commit' (default): Link to the commit that changed the file on GitHub.\n * - 'file': Link to the file in the repo at the upstream branch on GitHub.\n * - 'local': Deprecated (the upstream view worktree was replaced by browser diffs); treated as 'file'.\n */\n fileLinkMode?: 'commit' | 'file' | 'local';\n}\n\n/**\n * Configuration for a downstream fork repository that cella interacts with.\n *\n * Cella is the upstream/source-of-truth. For each fork it can:\n * - pull contributions FROM the fork's `pullBranch` (contributions service)\n * - run the normal temporary-branch sync flow inside the fork (forks service)\n */\nexport interface ForkConfig {\n /** Display name for the fork (also used as the contrib/<name> branch slug) */\n name: string;\n /** Local path to the fork repository (relative to this config or absolute) */\n localPath: string;\n /**\n * Git remote URL of the fork (e.g. 'git@github.com:org/fork.git').\n * When set, the contributions service fetches the fork's `pullBranch` from this\n * remote (the authoritative committed ref) instead of the local clone, so the\n * comparison no longer depends on the local checkout being up to date. The local\n * clone is still used to read the fork's owned-folder territory when available.\n */\n remoteUrl?: string;\n /** Fork branch that cella pulls contributions from (contributions service) */\n pullBranch: string;\n}\n\n/**\n * User-configurable sync options for cella/cella.config.ts.\n * Simplified for v2 - no long-lived sync branch or squash options.\n */\nexport interface CellaCliConfig {\n /** Core sync settings */\n settings: SyncSettings;\n\n /**\n * File overrides for controlling sync behavior per folder/file.\n */\n overrides?: {\n /**\n * Paths the fork fully owns — never synced (existing or new).\n * Exact paths or directory prefixes, not globs: 'bench' matches 'bench/' and\n * everything under it, 'README.md' matches that exact file.\n * Local territory: upstream cannot add, modify, or delete anything under these.\n */\n ignored?: string[];\n\n /**\n * Paths pinned to fork — fork wins on conflicts.\n * Exact paths or directory prefixes, not globs: 'bench' matches 'bench/' and\n * everything under it, 'README.md' matches that exact file.\n * Non-conflicting upstream changes merge normally.\n * If fork deleted a pinned file, deletion is respected.\n */\n pinned?: string[];\n };\n\n /**\n * Downstream fork repositories that cella interacts with (for upstream template repos).\n * When configured, the 'forks' and 'contributions' services appear in the CLI menu.\n */\n forks?: ForkConfig[];\n}\n\n/**\n * Helper function for defining cella/cella.config.ts with type checking.\n */\nexport function defineConfig(config: CellaCliConfig): CellaCliConfig {\n return config;\n}\n\n/**\n * Strict runtime schema mirroring {@link CellaCliConfig}.\n *\n * The TS interfaces above stay the source of truth (and keep their hover docs for\n * config authors). This schema is what's enforced at load time: `.strict()` rejects\n * unknown keys, so a typo like `ignoredFolders` instead of `ignored` fails closed\n * instead of silently dropping sync protection (tsx does not typecheck the config).\n *\n * The `satisfies z.ZodType<CellaCliConfig>` assertion keeps schema and interface in\n * lockstep: if either drifts (a renamed/removed/mis-typed field), TypeScript errors here.\n */\nexport const cellaConfigSchema = z\n .object({\n settings: z\n .object({\n upstreamUrl: z.string().min(1),\n upstreamBranch: z.string().min(1).optional(),\n upstreamTrack: z.enum(['release', 'branch']).optional(),\n releaseBase: z.string().min(1).optional(),\n packageJsonSync: z\n .array(\n z.enum([\n 'dependencies',\n 'devDependencies',\n 'peerDependencies',\n 'optionalDependencies',\n 'scripts',\n 'engines',\n 'packageManager',\n 'overrides',\n 'pnpm',\n ]),\n )\n .optional(),\n syncWithPackages: z.boolean().optional(),\n fileLinkMode: z.enum(['commit', 'file', 'local']).optional(),\n })\n .strict(),\n overrides: z\n .object({\n ignored: z.array(z.string()).optional(),\n pinned: z.array(z.string()).optional(),\n })\n .strict()\n .optional(),\n forks: z\n .array(\n z\n .object({\n name: z.string().min(1),\n localPath: z.string().min(1),\n remoteUrl: z.string().optional(),\n pullBranch: z.string().min(1),\n })\n .strict(),\n )\n .optional(),\n })\n .strict() satisfies z.ZodType<CellaCliConfig>;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL TYPES - for sync modules\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Sync services available in the CLI */\nexport type SyncService = 'analyze' | 'sync' | 'audit' | 'forks' | 'contributions' | 'stats';\n\n/** Analyze output scope for interactive and machine-readable flows */\nexport type AnalyzeScope = 'all' | 'risk' | 'protected';\n\n/** Runtime configuration with all resolved values */\nexport interface RuntimeConfig extends CellaCliConfig {\n /** Resolved fork repository path */\n forkPath: string;\n\n /** Full upstream remote ref (e.g., 'cella-upstream/development') */\n upstreamRef: string;\n\n /** Selected sync service */\n service: SyncService;\n\n /** Write full file list to log file */\n logFile: boolean;\n\n /** Non-interactive list output (for LLM/agent usage) */\n list: boolean;\n\n /** Machine-readable JSON output (for tooling/agent usage) */\n json: boolean;\n\n /** Print the unified diff for a single contributed file, then exit (contributions; for tooling/agents) */\n diff?: string;\n\n /** Open a browser diff for one file, then exit (analyze) */\n openDiff?: string;\n\n /** Scope of files returned in analyze list/json output */\n scope?: AnalyzeScope;\n\n /** Show verbose output */\n verbose: boolean;\n\n /** Pre-selected fork name (skips fork selection prompt) */\n fork?: string;\n\n /** Overwrite drifted files with upstream version (aggressive realignment) */\n hard?: boolean;\n\n /**\n * Disable pinned entries (cella/cella.config.ts overrides.pinned) for this sync so upstream\n * versions surface as behind/diverged. Managed files stay pinned because cella\n * handles them separately. Like --hard, uses the natural merge-base to resurface\n * full upstream history.\n */\n unpinned?: boolean;\n\n /**\n * Override upstream tracking for this run (analyze/sync), ignoring `settings.upstreamTrack`.\n * 'branch' follows the upstream branch tip (bleeding edge); 'release' uses a release tag.\n */\n track?: 'release' | 'branch';\n\n /** Bypass pnpm metadata cache for fresh registry data (audit service) */\n force?: boolean;\n\n /** Check which pnpm.overrides are still needed (audit service) */\n checkOverrides?: boolean;\n\n /** Regenerate test coverage before showing the stats summary (stats service) */\n coverage?: boolean;\n\n /**\n * After opening the sync PR, enable GitHub auto-merge (squash) so it merges itself once\n * required checks pass (sync service). Opt-in per run via `--direct-merge`; needs auto-merge\n * enabled on the repo. Not the advised default — a sync PR is usually worth a human look.\n */\n directMerge?: boolean;\n}\n\n/** File status after analysis */\nexport type FileStatus =\n | 'identical' // No changes needed\n | 'ahead' // Fork is ahead, protected (pinned/ignored)\n | 'local' // Local file (never existed upstream)\n | 'drifted' // Fork is ahead, NOT protected (at risk)\n | 'behind' // Upstream has changes to sync\n | 'diverged' // Both changed, will merge\n | 'pinned' // Fork wins on conflict\n | 'ignored' // Excluded from sync entirely\n | 'deleted' // Fork deleted, will stay deleted\n | 'renamed'; // Upstream renamed file\n\n/** Analyzed file with status and metadata */\nexport interface AnalyzedFile {\n path: string;\n status: FileStatus;\n /** True if file is in ignored list */\n isIgnored: boolean;\n /** True if file is in pinned list */\n isPinned: boolean;\n /** True if file exists in fork */\n existsInFork: boolean;\n /** True if file exists in upstream */\n existsInUpstream: boolean;\n /** True if file has merge conflict */\n hasConflict?: boolean;\n /** Relative date when file was last changed (since merge-base) */\n changedAt?: string;\n /** Unix epoch seconds of the last change, for sorting */\n changedTs?: number;\n /** Short commit hash of the last change */\n changedCommit?: string;\n /** For diverged files: relative date of upstream change */\n upstreamChangedAt?: string;\n /** For diverged files: Unix epoch seconds of the upstream change, for sorting */\n upstreamChangedTs?: number;\n /** For diverged files: short commit hash of the upstream change */\n upstreamCommit?: string;\n /** For renamed files: the original path before rename */\n renamedFrom?: string;\n}\n\n/** Summary counts by status */\nexport interface AnalysisSummary {\n /** Changed package/config files that are handled separately from normal sync categories */\n managed: number;\n identical: number;\n ahead: number;\n local: number;\n drifted: number;\n behind: number;\n diverged: number;\n pinned: number;\n ignored: number;\n deleted: number;\n renamed: number;\n total: number;\n}\n\n/** Merge result from merge-engine */\nexport interface MergeResult {\n success: boolean;\n /** Upstream branch name for file links */\n upstreamBranch?: string;\n /** Resolved concrete upstream ref that was merged (branch ref or release tag ref) */\n upstreamRef?: string;\n /** Upstream release tag synced (when tracking releases) */\n upstreamTag?: string;\n files: AnalyzedFile[];\n summary: AnalysisSummary;\n conflicts: string[];\n /** Upstream GitHub URL base for commit links */\n upstreamGitHubUrl?: string;\n /** Upstream commit info */\n upstreamCommit?: {\n hash: string;\n message: string;\n date: string;\n };\n /** Commits included in this sync range (oldest-first when rendered) */\n upstreamCommits?: Array<{\n hash: string;\n message: string;\n date: string;\n }>;\n /** Files that were auto-merged by git (diverged without remaining conflicts) */\n autoMergedFiles?: string[];\n}\n","/**\n * Files that cella manages outside the normal file sync categories.\n */\n\n/** Sync config path, relative to the fork repo root. Fork-owned, never synced from upstream. */\nexport const CONFIG_FILE = 'cella/cella.config.ts';\n\n/**\n * Legacy config path, before the config moved into `cella/`. Kept so the one sync that\n * performs the root→`cella/` move still recognizes the file as managed at its old path:\n * during that move git may present the change under the old path (or as a delete+add that\n * skips rename detection), and an exact match on the new path alone would let it fall\n * through to a normal — conflicting — merge. Harmless to match forever; it can only appear\n * on the move sync of a not-yet-migrated fork.\n */\nexport const LEGACY_CONFIG_FILE = 'cella.config.ts';\n\n/** Every path the sync config has lived at. Compared against to always-ignore across the move. */\nexport const CONFIG_FILE_PATHS: readonly string[] = [CONFIG_FILE, LEGACY_CONFIG_FILE];\n\n/**\n * Check if a file path is the sync config, at its current or legacy (pre-`cella/`) path.\n */\nexport function isConfigFile(filePath: string): boolean {\n return CONFIG_FILE_PATHS.includes(filePath);\n}\n\n/**\n * Check if a file path is a package.json file.\n */\nexport function isPackageJson(filePath: string): boolean {\n return filePath === 'package.json' || filePath.endsWith('/package.json');\n}\n\n/**\n * Check if a file path is managed by cella outside normal file sync categories.\n */\nexport function isManagedFile(filePath: string): boolean {\n return isPackageJson(filePath) || filePath === 'pnpm-lock.yaml' || isConfigFile(filePath);\n}\n","/**\n * Static analysis of module ownership for sync CLI.\n *\n * Each module declares ownership via a `registerModule`, `defineBackendModule`, or\n * `defineFrontendModule` call ({ owner, ... }) in its `*-module.ts` file.\n * Modules with `owner: 'app'` are fork-specific: their\n * source folders, plus matching frontend static asset folders when present, are\n * fork territory and must never be added, modified, or deleted by upstream during\n * sync — nor offered back upstream by the contributions service.\n *\n * Parsing is syntax-only (no type-checker), so it is fast and tolerant of\n * formatting, comments, and property order. Built on ts-morph so the same\n * project/AST approach can be reused for other source-introspection tasks.\n */\n\nimport { existsSync } from 'node:fs';\nimport { basename, join, relative, sep } from 'node:path';\nimport { Project, SyntaxKind } from 'ts-morph';\n\n/** Glob patterns (relative to repo root) for module definition files. */\nconst MODULE_FILE_GLOBS = [\n 'backend/src/modules/*/*-module.ts',\n 'frontend/src/modules/*/*-module.ts',\n 'frontend/src/modules/*/*-module.tsx',\n];\n\n/** Call names that register a module and carry its `owner` in the first argument. */\nconst MODULE_REGISTER_CALLS = new Set(['registerModule', 'defineBackendModule', 'defineFrontendModule']);\nconst FRONTEND_STATIC_ROOT = 'frontend/public/static';\n\n/**\n * Read the string value of an object literal's `owner` property, if present.\n */\nfunction readOwner(call: import('ts-morph').CallExpression): string | undefined {\n const arg = call.getArguments()[0]?.asKind(SyntaxKind.ObjectLiteralExpression);\n const initializer = arg?.getProperty('owner')?.asKind(SyntaxKind.PropertyAssignment)?.getInitializer();\n return initializer?.asKind(SyntaxKind.StringLiteral)?.getLiteralValue();\n}\n\n/**\n * Scan a repository for module territory owned by the app (`owner: 'app'`).\n *\n * @param repoPath - Absolute path to the repository root to scan.\n * @returns Repo-relative folder paths (POSIX separators), deduplicated.\n */\nexport function resolveAppModuleFolders(repoPath: string): string[] {\n const project = new Project({\n skipAddingFilesFromTsConfig: true,\n skipFileDependencyResolution: true,\n skipLoadingLibFiles: true,\n });\n\n const sourceFiles = project.addSourceFilesAtPaths(MODULE_FILE_GLOBS.map((glob) => `${repoPath}/${glob}`));\n\n const folders = new Set<string>();\n const moduleNames = new Set<string>();\n\n for (const sourceFile of sourceFiles) {\n const ownsApp = sourceFile\n .getDescendantsOfKind(SyntaxKind.CallExpression)\n .some((call) => MODULE_REGISTER_CALLS.has(call.getExpression().getText()) && readOwner(call) === 'app');\n\n if (!ownsApp) continue;\n\n const folder = relative(repoPath, sourceFile.getDirectoryPath()).split(sep).join('/');\n folders.add(folder);\n moduleNames.add(basename(folder));\n }\n\n for (const moduleName of moduleNames) {\n const staticFolder = `${FRONTEND_STATIC_ROOT}/${moduleName}`;\n if (existsSync(join(repoPath, staticFolder))) {\n folders.add(staticFolder);\n }\n }\n\n return [...folders];\n}\n","/**\n * Display utilities for sync CLI v2.\n *\n * Handles console output formatting, progress tracking, and result display.\n */\n\nimport { writeFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport process from 'node:process';\nimport packageJson from '../../package.json' with { type: 'json' };\nimport type { AnalysisSummary, AnalyzedFile, FileStatus, MergeResult } from '../config/types';\nimport pc from './colors';\nimport { getEnv } from './env';\nimport { isManagedFile } from './managed-files';\n\n/** CLI name */\nexport const NAME = 'cella cli';\n\n/** Version from package.json */\nexport const VERSION = packageJson.version;\n\n/** Options for generating links in CLI output */\nexport interface LinkOptions {\n /** Base GitHub URL for upstream (e.g., 'https://github.com/cellajs/cella') */\n upstreamGitHubUrl?: string;\n /** Upstream branch name for file links */\n upstreamBranch?: string;\n /** File link mode: 'commit' links to commit, 'file' links to file in repo ('local' is deprecated, treated as 'file') */\n fileLinkMode?: 'commit' | 'file' | 'local';\n /** Fork repository path for resolving file paths */\n forkPath?: string;\n}\n\n/** Line divider */\nexport const DIVIDER = '─'.repeat(60);\n\n/** Warning mark for non-fatal warnings */\nexport const warningMark = pc.yellow('⚠');\n\n/** Check mark for successful status lines */\nexport const checkMark = pc.green('✓');\n\ninterface Spinner {\n text: string;\n start(): Spinner;\n stop(): void;\n}\n\nclass TerminalSpinner implements Spinner {\n private readonly frames = ['-', '\\\\', '|', '/'];\n private frameIndex = 0;\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly enabled: boolean;\n\n constructor(\n public text: string,\n isSilent: boolean,\n ) {\n this.enabled = !isSilent && !!process.stdout.isTTY;\n }\n\n start(): Spinner {\n if (!this.enabled || this.timer) return this;\n\n this.render();\n this.timer = setInterval(() => {\n this.frameIndex = (this.frameIndex + 1) % this.frames.length;\n this.render();\n }, 80);\n\n return this;\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n\n if (!this.enabled) return;\n\n process.stdout.write('\\r\\x1b[2K');\n }\n\n private render(): void {\n process.stdout.write(`\\r${pc.cyan(this.frames[this.frameIndex])} ${this.text}`);\n }\n}\n\n/** Active spinner reference */\nlet activeSpinner: Spinner | null = null;\n\n/**\n * When true, stdout is reserved for machine-readable payloads (e.g. `--json`),\n * so all human-facing output (header, warnings, steps, spinner) is routed to stderr.\n */\nlet jsonMode = false;\n\n/**\n * Enable JSON mode: keep stdout clean for the JSON payload by sending every\n * human-facing line (console.info/console.warn, header, spinner) to stderr.\n * This makes `cella --json ... | jq` pipe cleanly.\n */\nexport function setJsonMode(enabled: boolean): void {\n jsonMode = enabled;\n if (!enabled) return;\n const toStderr = (...args: unknown[]) => {\n process.stderr.write(`${args.map((a) => (typeof a === 'string' ? a : String(a))).join(' ')}\\n`);\n };\n console.info = toStderr;\n console.log = toStderr;\n console.warn = toStderr;\n}\n\n/** Write a machine-readable payload to stdout (bypasses the stderr routing of JSON mode). */\nexport function writeStdout(text: string): void {\n process.stdout.write(text.endsWith('\\n') ? text : `${text}\\n`);\n}\n\n/**\n * Get the header line for CLI output.\n */\nfunction getHeader(): string {\n const right = 'cellajs.com';\n // Account for ANSI codes when calculating padding\n const visibleLeft = `⧈ ${NAME} v${VERSION}`;\n const padding = Math.max(1, 60 - visibleLeft.length - right.length);\n return `${pc.cyan(`⧈ ${NAME}`)}${pc.dim(` · v${VERSION}`)}${pc.cyan(`${' '.repeat(padding)}${right}`)}`;\n}\n\n/**\n * Print the welcome header.\n */\nexport function printHeader(): void {\n console.info();\n console.info(getHeader());\n console.info(DIVIDER);\n console.info();\n}\n\n/**\n * Print a completed step with checkmark.\n * Optionally include a detail line in grey, followed by a blank line.\n */\nfunction printStep(label: string, detail?: string): void {\n console.info(`${checkMark} ${label}`);\n if (detail) {\n console.info(` ${pc.dim(detail)}`);\n console.info(); // blank line after detail block\n }\n}\n\n/**\n * Create a progress spinner.\n * Uses isSilent in test environments to suppress output.\n */\nexport function createSpinner(text: string): Spinner {\n const isTestEnv = !!getEnv('VITEST') || getEnv('NODE_ENV') === 'test';\n activeSpinner = new TerminalSpinner(text, isTestEnv || jsonMode);\n activeSpinner.start();\n return activeSpinner;\n}\n\n/**\n * Stop the active spinner with success and print step.\n */\nexport function spinnerSuccess(message?: string, detail?: string): void {\n stopSpinner();\n if (message) {\n printStep(message, detail);\n }\n}\n\n/**\n * Stop the active spinner with failure.\n */\nexport function spinnerFail(message: string): void {\n stopSpinner();\n console.info(`${pc.red('✗')} ${message}`);\n}\n\n/**\n * Update spinner text.\n */\nexport function spinnerText(text: string): void {\n if (activeSpinner) {\n activeSpinner.text = text;\n }\n}\n\n/**\n * Stop and clear the active spinner.\n */\nfunction stopSpinner(): void {\n if (activeSpinner) {\n activeSpinner.stop();\n activeSpinner = null;\n }\n}\n\n/**\n * Create a clickable hyperlink for terminals that support OSC 8.\n * Falls back to just the label if no URL provided.\n */\nexport function hyperlink(label: string, url?: string): string {\n if (!url) return label;\n // Strip control characters from URL to prevent terminal escape injection (CWE-116)\n // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping control chars is the security purpose here.\n const safeUrl = url.replace(/[\\x00-\\x1f\\x7f]/g, '');\n // OSC 8 hyperlink format: \\x1b]8;;URL\\x07LABEL\\x1b]8;;\\x07\n return `\\x1b]8;;${safeUrl}\\x07${label}\\x1b]8;;\\x07`;\n}\n\n/**\n * Build a VS Code deep link that opens a file from the fork workspace.\n */\nfunction getVsCodeOpenFileLink(filePath: string, options: LinkOptions): string {\n const { forkPath } = options;\n if (!forkPath) return filePath;\n\n const absolutePath = resolve(forkPath, filePath);\n const url = `vscode://file${absolutePath}`;\n return hyperlink(filePath, url);\n}\n\n/** Commit info used for sync progress output */\nexport interface SyncCommitInfo {\n hash: string;\n message: string;\n date: string;\n}\n\n/**\n * Format the fetched-upstream detail block with clickable short commit hashes.\n */\nexport function formatFetchedUpstreamDetail(\n commitCount: number,\n commits: SyncCommitInfo[],\n upstreamGitHubUrl?: string,\n maxShownCommits = 50,\n): string {\n const commitLabel = commitCount === 1 ? '1 new commit' : `${commitCount} new commits`;\n const lines = [`${commitLabel} since last merge`];\n\n const shown = commits.slice(0, maxShownCommits);\n for (const commit of shown) {\n const shortHash = commit.hash.slice(0, 7);\n const commitUrl = upstreamGitHubUrl ? `${upstreamGitHubUrl}/commit/${commit.hash}` : undefined;\n const hashLabel = hyperlink(shortHash, commitUrl);\n lines.push(` ${hashLabel} \"${commit.message}\" (${commit.date})`);\n }\n\n if (commitCount > shown.length) {\n lines.push(` ... and ${commitCount - shown.length} more`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Generate a link for a file based on link style.\n * Returns { label, url } for use with hyperlink().\n */\nfunction getFileLink(\n filePath: string,\n commitHash: string | undefined,\n options: LinkOptions,\n): { label: string; url?: string } {\n const { upstreamGitHubUrl, upstreamBranch, fileLinkMode = 'commit' } = options;\n // 'local' linked into the upstream view worktree before browser diffs replaced it.\n const mode = fileLinkMode === 'local' ? 'file' : fileLinkMode;\n\n if (!upstreamGitHubUrl) {\n return { label: commitHash?.slice(0, 9) || '' };\n }\n\n if (mode === 'file' && upstreamBranch) {\n // Link to file in repo: https://github.com/org/repo/blob/branch/path/to/file\n const url = `${upstreamGitHubUrl}/blob/${upstreamBranch}/${filePath}`;\n return { label: filePath.split('/').pop() || filePath, url };\n }\n\n // Default: link to commit\n if (commitHash) {\n const url = `${upstreamGitHubUrl}/commit/${commitHash}`;\n return { label: commitHash.slice(0, 9), url };\n }\n\n return { label: '' };\n}\n\n/**\n * Print a section header with title and divider.\n */\nfunction printSectionHeader(title: string): void {\n console.info();\n console.info(title);\n console.info(DIVIDER);\n console.info();\n}\n\n/**\n * Format file date info with link for display.\n */\nfunction formatFileDateInfo(\n filePath: string,\n commit: string | undefined,\n date: string | undefined,\n linkOptions: LinkOptions,\n): string {\n const link = getFileLink(filePath, commit, linkOptions);\n const linkLabel = link.label ? hyperlink(link.label, link.url) : '';\n return date ? pc.dim(` ≠ ${date} ${linkLabel}`) : '';\n}\n\n/**\n * Format merge-in-progress detail with conflicts and auto-merged file links.\n */\nexport function formatMergeInProgressDetail(\n conflictCount: number,\n autoMergedFiles: string[],\n linkOptions: LinkOptions,\n maxFiles = 100,\n): string {\n const lines = [`${conflictCount} conflicts to resolve in IDE`];\n\n if (autoMergedFiles.length === 0) {\n return lines.join('\\n');\n }\n\n lines.push('');\n lines.push(` auto-merged files (${autoMergedFiles.length}):`);\n\n const shown = autoMergedFiles.slice(0, maxFiles);\n for (const filePath of shown) {\n const fileLink = getVsCodeOpenFileLink(filePath, linkOptions);\n lines.push(` - ${fileLink}`);\n }\n\n if (autoMergedFiles.length > shown.length) {\n lines.push(` ... + ${autoMergedFiles.length - shown.length} more`);\n }\n\n return lines.join('\\n');\n}\n\n/** Display configuration for a file status */\ninterface StatusConfig {\n icon: string;\n label: string;\n color: (text: string) => string;\n description?: string;\n}\n\ntype SummaryStatus = FileStatus | 'managed';\n\n/** Unified status display config: icon, label, color, and description for each status. Key order defines sort priority. */\nconst statusConfig: Record<FileStatus, StatusConfig> = {\n behind: { icon: pc.cyan('↓'), label: 'behind', color: pc.cyan, description: 'upstream changed, will sync' },\n diverged: { icon: pc.magenta('⇅'), label: 'diverged', color: pc.magenta, description: 'both changed, will merge' },\n drifted: { icon: pc.yellow('!'), label: 'drifted', color: pc.yellow, description: 'fork changed (at risk)' },\n ahead: { icon: pc.blue('↑'), label: 'ahead', color: pc.blue, description: 'fork changed (protected)' },\n local: { icon: pc.green('+'), label: 'local', color: pc.green, description: 'local file in cella folders' },\n pinned: { icon: pc.green('⨀'), label: 'pinned', color: pc.green, description: 'both changed, fork wins' },\n ignored: { icon: pc.gray('⨂'), label: 'ignored', color: pc.gray },\n identical: { icon: pc.gray('✓'), label: 'identical', color: pc.gray, description: 'no changes' },\n deleted: { icon: pc.red('✗'), label: 'deleted', color: pc.red },\n renamed: { icon: pc.blue('→'), label: 'renamed', color: pc.blue },\n};\n\nconst summaryStatusConfig: Record<SummaryStatus, StatusConfig> = {\n ...statusConfig,\n managed: {\n icon: pc.cyan('◇'),\n label: 'managed',\n color: pc.cyan,\n description: 'package.jsons & cella/cella.config.ts handled separately',\n },\n ignored: { ...statusConfig.ignored, description: 'protected by ignored config' },\n};\n\n/** Ordered status keys derived from statusConfig key order */\nconst statusOrder = Object.keys(statusConfig) as FileStatus[];\n\n/**\n * Print the analysis summary.\n */\nexport function printSummary(summary: AnalysisSummary, title = 'summary'): void {\n printSectionHeader(pc.cyan(title));\n\n // Format counts with padding.\n const maxCount = Math.max(\n summary.managed,\n summary.ignored,\n summary.identical,\n summary.ahead,\n summary.local,\n summary.drifted,\n summary.behind,\n summary.diverged,\n summary.pinned,\n summary.deleted,\n summary.renamed,\n );\n const countWidth = String(maxCount).length + 1;\n\n // Helper to print a status line using unified config\n const printLine = (status: SummaryStatus, count: number) => {\n const { icon, label, color, description } = summaryStatusConfig[status];\n const countStr = color(String(count).padStart(countWidth));\n const desc = description ? pc.dim(description) : '';\n console.info(` ${icon} ${countStr} ${label.padEnd(15)}${desc}`);\n };\n\n // Grouped layout with blank lines between groups\n printLine('managed', summary.managed);\n printLine('ignored', summary.ignored);\n\n console.info();\n printLine('identical', summary.identical);\n\n console.info();\n printLine('ahead', summary.ahead);\n printLine('local', summary.local);\n printLine('drifted', summary.drifted);\n\n console.info();\n printLine('diverged', summary.diverged);\n printLine('pinned', summary.pinned);\n\n console.info();\n printLine('behind', summary.behind);\n}\n\n/**\n * Print a group of files with a specific status, including section header and footer.\n */\nfunction printFileGroup(\n files: AnalyzedFile[],\n status: FileStatus,\n linkOptions: LinkOptions,\n options?: {\n /** Override section header title */\n title?: string;\n /** Footer hint text (dimmed) */\n hint?: string;\n /** Which commit/date fields to use: 'fork' or 'upstream' */\n dateSource?: 'fork' | 'upstream';\n },\n): void {\n const filtered = files.filter((f) => f.status === status && !isManagedFile(f.path));\n if (filtered.length === 0) return;\n\n const config = statusConfig[status];\n const title = options?.title ?? `${config.icon} ${config.label}`;\n\n printSectionHeader(`${title} ${pc.dim(`· ${filtered.length} files`)}`);\n\n const useUpstream = options?.dateSource === 'upstream';\n const maxLines = 100;\n const shown = filtered.length > maxLines ? filtered.slice(0, maxLines) : filtered;\n\n for (const file of shown) {\n const commit = useUpstream ? file.upstreamCommit : file.changedCommit;\n const date = useUpstream ? file.upstreamChangedAt : file.changedAt;\n const dateInfo = formatFileDateInfo(file.path, commit, date, linkOptions);\n console.info(` ${config.icon} ${file.path}${dateInfo}`);\n }\n\n if (filtered.length > maxLines) {\n console.info(pc.dim(` ... + ${filtered.length - maxLines} more`));\n }\n\n if (options?.hint) {\n console.info();\n console.info(pc.dim(` ${options.hint}`));\n }\n}\n\n/**\n * Print all analyze-mode file group sections in review order:\n * behind, ahead (protected), drifted, diverged, and pinned.\n */\nexport function printAnalysisFileGroups(files: AnalyzedFile[], linkOptions: LinkOptions): void {\n printFileGroup(files, 'behind', linkOptions, {\n title: pc.cyan('↓ behind on upstream'),\n });\n printFileGroup(files, 'ahead', linkOptions, {\n title: `${pc.blue('↑ protected in fork')}`,\n hint: 'these files have fork changes but are protected (pinned).',\n });\n printFileGroup(files, 'drifted', linkOptions, {\n title: `${warningMark} ${pc.yellow('drifted from upstream')}`,\n hint: 'these files have fork changes but are not pinned or ignored.',\n });\n printFileGroup(files, 'diverged', linkOptions, {\n title: `${pc.magenta('⇅ diverged')}`,\n hint: 'both fork and upstream changed.',\n dateSource: 'upstream',\n });\n printFileGroup(files, 'pinned', linkOptions, {\n title: `${pc.green('⨀ pinned')}`,\n hint: 'both changed, fork wins (pinned in cella/cella.config.ts).',\n dateSource: 'upstream',\n });\n}\n\n/**\n * Write full file list to log file.\n */\nexport function writeLogFile(forkPath: string, files: AnalyzedFile[]): string {\n const logPath = join(forkPath, 'cella-sync.log');\n\n const lines: string[] = [\n `cella sync analysis - ${new Date().toISOString()}`,\n DIVIDER,\n '',\n `complete file list (${files.length} files)`,\n DIVIDER,\n '',\n ];\n\n // Sort files by status, then path\n const sortedFiles = [...files].sort((a, b) => {\n const aOrder = statusOrder.indexOf(a.status);\n const bOrder = statusOrder.indexOf(b.status);\n if (aOrder !== bOrder) return aOrder - bOrder;\n return a.path.localeCompare(b.path);\n });\n\n for (const file of sortedFiles) {\n const config = statusConfig[file.status];\n // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping ANSI escape sequences requires \\x1b literal.\n const icon = config.icon.replace(/\\x1b\\[[0-9;]*m/g, ''); // Strip ANSI\n lines.push(` ${icon} ${config.label.padEnd(12)} ${file.path}`);\n }\n\n writeFileSync(logPath, lines.join('\\n'), 'utf-8');\n return logPath;\n}\n\n/**\n * Print sync completion message.\n */\nexport function printSyncComplete(result: MergeResult, options: { stagedBranch?: string } = {}): void {\n const updated = result.files.filter((file) => file.status === 'behind' || file.status === 'diverged').length;\n const diverged = result.files.filter((file) => file.status === 'diverged').length;\n const merged = result.autoMergedFiles?.length ?? Math.max(0, diverged - result.conflicts.length);\n const conflicts = result.conflicts.length;\n\n console.info();\n if (options.stagedBranch) {\n console.info(`${pc.green('✓')} Sync merge staged on '${options.stagedBranch}'`);\n console.info(\n pc.dim(\n ` ${updated} files updated, ${merged} auto-merged, ${conflicts} conflicts. Review, then rerun \\`pnpm cella sync\\` to finish.`,\n ),\n );\n } else {\n console.info(`${pc.green('✓')} sync complete`);\n console.info(pc.dim(` ${updated} files updated, ${merged} auto-merged, ${conflicts} conflicts`));\n }\n\n console.info();\n}\n\n/**\n * Print warnings for aggressive sync flags (--hard / --unpinned) after completion.\n *\n * Explains what each active flag did and its consequence, and adds a shared\n * caution to cherry-pick deliberately when either is used.\n */\n/**\n * A pinned file whose fork content is byte-identical to the previous upstream (status\n * `behind`) never actually diverged — the pin is silently freezing it at the old upstream\n * version and dropping upstream's new changes. Because the fork copy equals the old\n * upstream, this produces no merge conflict and no type error, so it slips through unseen\n * (e.g. a pinned nav-config losing new upstream entries). These are the pins worth a look.\n */\nexport function findMaskingPins(files: AnalyzedFile[]): AnalyzedFile[] {\n return files.filter(\n (file) => file.isPinned && file.status === 'behind' && file.existsInFork && file.existsInUpstream,\n );\n}\n\n/**\n * Warn when pins are masking upstream changes (see `findMaskingPins`). Silent by design\n * when there is nothing to report, so it is safe to call unconditionally after a summary.\n */\nexport function printMaskingPinWarning(files: AnalyzedFile[]): void {\n const masking = findMaskingPins(files);\n if (masking.length === 0) return;\n\n const many = masking.length > 1;\n console.info();\n console.info(\n `${warningMark} ${pc.yellow(\n `${masking.length} pinned ${many ? 'files match' : 'file matches'} the previous upstream but changed upstream —`,\n )}`,\n );\n console.info(pc.yellow(' the pin keeps the old fork copy and silently drops those upstream changes:'));\n for (const file of masking) {\n console.info(pc.dim(` ⨀ ${file.path}`));\n }\n console.info(\n pc.yellow(' If the fork never customized these, unpin them in cella/cella.config.ts to take upstream.'),\n );\n console.info();\n}\n\nexport function printFlagWarnings(options: { hard?: boolean; unpinned?: boolean }): void {\n const { hard, unpinned } = options;\n if (!hard && !unpinned) return;\n\n if (hard) {\n console.info(pc.yellow('⚠ --hard used: drifted files were treated as behind, overwriting with incoming.'));\n }\n if (unpinned) {\n console.info(\n pc.yellow(\n '⚠ --unpinned used: pinned files in cella/cella.config.ts were ignored, this can result in more drifts.',\n ),\n );\n }\n console.info(pc.yellow(' Be extra careful & cherrypick what you want only.'));\n console.info();\n}\n","{\n \"name\": \"@cellajs/cli\",\n \"version\": \"0.1.1\",\n \"private\": false,\n \"license\": \"MIT\",\n \"description\": \"CLI for managing your monorepo and syncing with upstream Cella.\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/cellajs/cella-cli\"\n },\n \"homepage\": \"https://cellajs.com\",\n \"author\": \"CellaJS <info@cellajs.com>\",\n \"engines\": {\n \"node\": \"24.x\"\n },\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"exports\": {\n \".\": \"./dist/index.js\",\n \"./config\": {\n \"types\": \"./dist/config.d.ts\",\n \"import\": \"./dist/config.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\",\n \"index.js\",\n \"README.md\"\n ],\n \"bin\": {\n \"cella\": \"index.js\"\n },\n \"imports\": {\n \"#/*\": \"./src/*\"\n },\n \"scripts\": {\n \"start\": \"tsx index.ts\",\n \"clean\": \"rimraf ./dist\",\n \"build\": \"tsup\",\n \"test-build\": \"pnpm run build && node index.js --help\",\n \"prepublishOnly\": \"pnpm run test:release\",\n \"check\": \"pnpm ts && pnpm biome check --write .\",\n \"ts\": \"tsgo --pretty\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"test\": \"vitest run\",\n \"test:release\": \"pnpm run build && vitest run --config vitest.release.config.ts\",\n \"test:watch\": \"vitest\",\n \"prepare\": \"lefthook install\"\n },\n \"dependencies\": {\n \"@inquirer/core\": \"^11.2.1\",\n \"@inquirer/prompts\": \"^8.5.2\",\n \"@pierre/diffs\": \"^1.2.12\",\n \"commander\": \"^15.0.0\",\n \"ts-morph\": \"^28.0.0\",\n \"zod\": \"^4.4.3\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.5.2\",\n \"@commitlint/cli\": \"^21.2.0\",\n \"@commitlint/config-conventional\": \"^21.2.0\",\n \"@evilmartians/lefthook\": \"^2.1.9\",\n \"@types/node\": \"24.10.13\",\n \"@typescript/native-preview\": \"7.0.0-dev.20260702.3\",\n \"rimraf\": \"^6.1.3\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.22.4\",\n \"typescript\": \"^6.0.3\",\n \"vitest\": \"^4.1.9\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"keywords\": [\n \"cella\",\n \"cellajs\",\n \"cli\",\n \"sync\",\n \"template\"\n ],\n \"packageManager\": \"pnpm@11.8.0\",\n \"commitlint\": {\n \"extends\": [\n \"@commitlint/config-conventional\"\n ],\n \"rules\": {\n \"type-enum\": [\n 2,\n \"always\",\n [\n \"feat\",\n \"fix\",\n \"perf\",\n \"refactor\",\n \"revert\",\n \"docs\",\n \"chore\",\n \"build\",\n \"ci\",\n \"style\",\n \"test\"\n ]\n ],\n \"header-max-length\": [\n 2,\n \"always\",\n 120\n ],\n \"body-max-line-length\": [\n 0,\n \"always\",\n 200\n ],\n \"footer-max-line-length\": [\n 0,\n \"always\",\n 200\n ]\n }\n }\n}\n","/**\n * Override matching and validation utilities for sync CLI v2.\n *\n * Handles matching files against ignored/pinned paths and\n * validates config for potential issues.\n */\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { CellaCliConfig } from '../config/types';\nimport { warningMark } from './display';\nimport { isManagedFile } from './managed-files';\n\n/**\n * Check if a file path is owned by any of the given folders.\n *\n * Folders are directory prefixes (not globs): an entry matches the file when\n * the path equals the entry exactly or is nested under `entry + '/'`.\n *\n * @param filePath - The file path to test\n * @param folders - Folder prefixes (or exact paths) to match against\n */\nexport function isUnderAnyFolder(filePath: string, folders: string[]): boolean {\n return folders.some((folder) => {\n const entry = folder.replace(/\\/+$/, '');\n return filePath === entry || filePath.startsWith(`${entry}/`);\n });\n}\n\n/**\n * Check if a file is inside an ignored path.\n */\nexport function isIgnored(filePath: string, config: CellaCliConfig): boolean {\n return isUnderAnyFolder(filePath, config.overrides?.ignored || []);\n}\n\n/**\n * Check if a file is in the pinned list.\n * Managed files are always considered pinned (handled separately by cella).\n */\nexport function isPinned(filePath: string, config: CellaCliConfig): boolean {\n if (isManagedFile(filePath)) return true;\n return isUnderAnyFolder(filePath, config.overrides?.pinned || []);\n}\n\n/**\n * Resolve effective pin status for a sync run, honoring the --unpinned flag.\n *\n * When `unpinned` is true, configured pins are disabled so upstream versions\n * surface as behind/diverged — but managed files stay pinned (their content is\n * reconciled separately by cella).\n */\nexport function isPinnedForSync(filePath: string, config: CellaCliConfig, unpinned?: boolean): boolean {\n if (isManagedFile(filePath)) return true;\n if (unpinned) return false;\n return isPinned(filePath, config);\n}\n\n/** Validation warning */\ninterface ConfigWarning {\n type: 'pinned-glob' | 'pinned-not-found' | 'ignored-not-found';\n pattern: string;\n message: string;\n}\n\n/**\n * Check if an entry contains glob characters (no longer supported).\n */\nfunction hasGlobChars(entry: string): boolean {\n return entry.includes('*') || entry.includes('?');\n}\n\n/**\n * Validate config overrides and return warnings.\n *\n * Checks for:\n * - Pinned entries using glob patterns (no longer supported)\n * - Pinned entries that don't exist in fork\n * - Ignored entries that don't exist in fork\n *\n * @param config - The sync config to validate\n * @param forkPath - Path to the fork repository\n */\nexport function validateOverrides(config: CellaCliConfig, forkPath: string): ConfigWarning[] {\n const warnings: ConfigWarning[] = [];\n\n // Check pinned entries\n const pinned = config.overrides?.pinned || [];\n for (const entry of pinned) {\n if (hasGlobChars(entry)) {\n warnings.push({\n type: 'pinned-glob',\n pattern: entry,\n message: `pin uses glob (not supported, use a path or folder): ${entry}`,\n });\n } else if (!existsSync(join(forkPath, entry))) {\n warnings.push({\n type: 'pinned-not-found',\n pattern: entry,\n message: `pin not found: ${entry}`,\n });\n }\n }\n\n // Check ignored entries\n const ignored = config.overrides?.ignored || [];\n for (const entry of ignored) {\n if (hasGlobChars(entry)) {\n warnings.push({\n type: 'ignored-not-found',\n pattern: entry,\n message: `ignored entry uses glob (not supported, use a path or folder): ${entry}`,\n });\n } else if (!existsSync(join(forkPath, entry.replace(/\\/+$/, '')))) {\n warnings.push({\n type: 'ignored-not-found',\n pattern: entry,\n message: `ignored entry not found: ${entry}`,\n });\n }\n }\n\n return warnings;\n}\n\n/**\n * Print validation warnings to console.\n */\nexport function printWarnings(warnings: ConfigWarning[]): void {\n for (const warning of warnings) {\n console.info(`${warningMark} ${warning.message}`);\n }\n}\n","/**\n * Analyze service for sync CLI v2.\n *\n * Dry run of sync - shows what would change without applying.\n * Uses the same merge-engine as sync, but discards the result.\n */\n\nimport { basename } from 'node:path';\nimport type { MergeResult, RuntimeConfig } from '../config/types';\nimport pc from '../utils/colors';\nimport { gitDiffFile, openDiffInBrowser } from '../utils/diff';\nimport {\n createSpinner,\n type LinkOptions,\n printAnalysisFileGroups,\n printMaskingPinWarning,\n printSummary,\n spinnerSuccess,\n spinnerText,\n writeLogFile,\n writeStdout,\n} from '../utils/display';\nimport { runMergeEngine } from './merge-engine';\n\nconst scopeStatuses: Record<'all' | 'risk' | 'protected', Set<string>> = {\n all: new Set(['ahead', 'drifted', 'diverged']),\n risk: new Set(['drifted', 'diverged']),\n protected: new Set(['ahead']),\n};\n\nfunction filterByScope(files: MergeResult['files'], scope: 'all' | 'risk' | 'protected'): MergeResult['files'] {\n const statuses = scopeStatuses[scope];\n return files.filter((f) => statuses.has(f.status));\n}\n\nfunction findTargetFile(files: MergeResult['files'], targetPath: string) {\n const exact = files.find((f) => f.path === targetPath);\n if (exact) return exact;\n\n const normalized = targetPath.replace(/^\\.\\//, '');\n return files.find((f) => f.path === normalized);\n}\n\nfunction printUnifiedDiff(config: RuntimeConfig, filePath: string): void {\n // Label the upstream side 'cella/' and the local side with the repo's folder name\n // so the diff reads cella/<path> vs <fork>/<path> instead of opaque a/ and b/.\n const diff = gitDiffFile(config.forkPath, `${config.upstreamRef}..HEAD`, filePath, {\n dstPrefix: basename(config.forkPath),\n });\n writeStdout(diff.toString());\n}\n\n/**\n * Run the analyze service (dry run).\n *\n * Creates worktree, performs merge, shows results, discards worktree.\n */\nexport async function runAnalyze(config: RuntimeConfig): Promise<MergeResult> {\n createSpinner('starting analysis...');\n\n const result = await runMergeEngine(config, {\n apply: false,\n onProgress: (message) => {\n spinnerText(message);\n },\n onStep: (label, detail) => {\n spinnerSuccess(label, detail);\n createSpinner('...');\n },\n });\n\n spinnerSuccess();\n\n const scopedFiles = filterByScope(result.files, config.scope ?? 'all');\n\n if (config.diff) {\n const file = findTargetFile(scopedFiles, config.diff) ?? findTargetFile(result.files, config.diff);\n if (!file) throw new Error(`file not found in analysis results: ${config.diff}`);\n printUnifiedDiff(config, file.path);\n return result;\n }\n\n if (config.json) {\n const out = scopedFiles.map((f) => ({\n path: f.path,\n status: f.status,\n changedAt: f.changedAt ?? null,\n changedCommit: f.changedCommit ?? null,\n upstreamChangedAt: f.upstreamChangedAt ?? null,\n upstreamCommit: f.upstreamCommit ?? null,\n }));\n writeStdout(JSON.stringify(out, null, 2));\n return result;\n }\n\n if (config.list) {\n for (const file of scopedFiles) {\n console.info(file.path);\n }\n return result;\n }\n\n if (config.openDiff) {\n const file = findTargetFile(scopedFiles, config.openDiff) ?? findTargetFile(result.files, config.openDiff);\n if (!file) throw new Error(`file not found in analysis results: ${config.openDiff}`);\n\n // Diff the upstream ref against the working tree (single ref, no range) so\n // the rendered page includes uncommitted local changes — the same live view\n // the old VS Code diff gave.\n const patch = gitDiffFile(config.forkPath, config.upstreamRef, file.path);\n if (patch.length === 0) {\n console.info(`${pc.green('✓')} ${file.path} is identical to upstream`);\n return result;\n }\n\n const pagePath = await openDiffInBrowser(\n patch.toString(),\n {\n filePath: file.path,\n srcLabel: 'cella',\n dstLabel: basename(config.forkPath),\n note: 'local working tree',\n },\n config.forkPath,\n );\n console.info(`${pc.green('✓')} opened browser diff for ${file.path}`);\n console.info(pc.dim(` ${pagePath}`));\n return result;\n }\n\n // Build link options from result and config\n const linkOptions: LinkOptions = {\n upstreamGitHubUrl: result.upstreamGitHubUrl,\n upstreamBranch: result.upstreamBranch,\n fileLinkMode: config.settings.fileLinkMode,\n forkPath: config.forkPath,\n };\n\n // Print file lists first (analyze shows file lists for review)\n printAnalysisFileGroups(result.files, linkOptions);\n\n // Print summary at the end\n printSummary(result.summary, 'analysis summary');\n\n // Surface pins that would silently freeze a file at the old upstream on the next sync\n printMaskingPinWarning(result.files);\n\n // Write log file if requested\n if (config.logFile) {\n const logPath = writeLogFile(config.forkPath, result.files);\n console.info();\n console.info(pc.dim(`full file list written to: ${logPath}`));\n }\n\n console.info();\n\n return result;\n}\n","/**\n * Diff helpers for sync CLI v2.\n *\n * Shared logic for producing a single-file `git diff` and for rendering a diff\n * as a self-contained HTML page that opens in the default browser. Used by the\n * analyze and contributions services.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { basename, join } from 'node:path';\nimport process from 'node:process';\n\n/**\n * Run `git diff` for a single file.\n *\n * With `dstPrefix`, the sides are labeled `cella/<path>` vs `<dstPrefix>/<path>`\n * instead of opaque a/ and b/ — used for the `--diff` stdout mode where the\n * labels carry meaning. Without it, standard a/ b/ prefixes are kept, which the\n * HTML renderer's patch parser requires.\n *\n * @param cwd - Repo to run the diff in\n * @param range - Ref range (e.g. 'upstreamRef..HEAD'), or a single ref to diff\n * that ref against the working tree\n * @param filePath - File to diff\n * @returns Raw diff output (empty when the file is identical)\n */\nexport function gitDiffFile(\n cwd: string,\n range: string,\n filePath: string,\n options: { dstPrefix?: string } = {},\n): Buffer {\n const args = ['diff', '--no-color'];\n if (options.dstPrefix) args.push('--src-prefix=cella/', `--dst-prefix=${options.dstPrefix}/`);\n args.push(range, '--', filePath);\n\n try {\n return execFileSync('git', args, { cwd, maxBuffer: 50 * 1024 * 1024 });\n } catch (error) {\n const stderr = (error as { stderr?: Buffer }).stderr?.toString().trim();\n throw new Error(stderr || `failed to diff ${filePath}`);\n }\n}\n\n/** Labels shown in the header of a rendered diff page. */\nexport interface DiffPageMeta {\n /** File path shown in the page header and title */\n filePath: string;\n /** Label for the upstream side (e.g. 'cella') */\n srcLabel: string;\n /** Label for the local side (e.g. the fork name) */\n dstLabel: string;\n /** Extra context shown after the labels (e.g. 'includes uncommitted changes') */\n note?: string;\n}\n\nfunction escapeHtml(text: string): string {\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n}\n\n/**\n * Render a unified diff as a complete, self-contained HTML document.\n *\n * Highlighting and diff layout come from `@pierre/diffs` (Shiki-based), rendered\n * server-side to static HTML: no scripts, no external requests, adapts to the\n * viewer's light/dark preference. The patch must use standard a/ b/ prefixes\n * (call `gitDiffFile` without `dstPrefix`); side labels belong in `meta` instead.\n */\nexport async function renderDiffPage(patch: string, meta: DiffPageMeta): Promise<string> {\n // Lazy import: the CLI is a short-lived process and most invocations never\n // render a diff, so startup shouldn't pay Shiki's module-load cost.\n const { preloadPatchDiff } = await import('@pierre/diffs/ssr');\n\n const { prerenderedHTML } = await preloadPatchDiff({\n patch,\n options: {\n diffStyle: 'split',\n themeType: 'system',\n lineDiffType: 'word-alt',\n hunkSeparators: 'line-info',\n overflow: 'wrap',\n disableFileHeader: true,\n },\n });\n\n const title = `${escapeHtml(meta.filePath)} · ${escapeHtml(meta.srcLabel)} vs ${escapeHtml(meta.dstLabel)}`;\n const note = meta.note ? `<span class=\"note\">· ${escapeHtml(meta.note)}</span>` : '';\n\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${title}</title>\n<style>\n :root { color-scheme: light dark; }\n * { box-sizing: border-box; }\n body {\n margin: 0;\n font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;\n background: light-dark(#fafafa, #111);\n color: light-dark(#111, #eee);\n }\n header {\n display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap;\n padding: 0.9rem 1.25rem;\n border-bottom: 1px solid light-dark(#e2e2e2, #2a2a2a);\n position: sticky; top: 0;\n background: inherit;\n }\n header .brand { font-weight: 600; color: light-dark(#0891b2, #22d3ee); }\n header code { font-family: ui-monospace, monospace; font-size: 0.9rem; }\n header .sides { margin-left: auto; font-size: 0.8rem; opacity: 0.7; }\n main { max-width: 1400px; margin: 1rem auto; padding: 0 1rem 2rem; }\n .diff-shell {\n border: 1px solid light-dark(#e2e2e2, #2a2a2a);\n border-radius: 8px; overflow: hidden;\n background: light-dark(#fff, #161616);\n }\n</style>\n</head>\n<body>\n<header>\n <span class=\"brand\">⧈ cella diff</span>\n <code>${escapeHtml(meta.filePath)}</code>\n <span class=\"sides\">${escapeHtml(meta.srcLabel)} ← → ${escapeHtml(meta.dstLabel)} ${note}</span>\n</header>\n<main>\n <!-- Declarative shadow DOM: the library's CSS targets :host, which only\n matches inside a shadow root (its browser component renders into one). -->\n <div class=\"diff-shell\">\n <template shadowrootmode=\"open\">\n${prerenderedHTML}\n </template>\n </div>\n</main>\n</body>\n</html>`;\n}\n\n/** Open a file or URL with the platform's default handler (best-effort: a\n * missing or failing opener is not fatal — the page path is printed anyway). */\nfunction openWithDefaultApp(target: string): void {\n try {\n if (process.platform === 'win32') {\n execFileSync('rundll32', ['url.dll,FileProtocolHandler', target], { stdio: 'ignore' });\n } else {\n execFileSync(process.platform === 'darwin' ? 'open' : 'xdg-open', [target], { stdio: 'ignore' });\n }\n } catch {\n // e.g. headless environment without a browser/opener\n }\n}\n\n/**\n * Render a diff page, write it to a stable temp path, and open it in the browser.\n *\n * The output path is keyed by repo name and file path and overwritten on each\n * view, so repeat views don't litter tmp and a browser refresh shows the latest\n * render.\n *\n * @returns Absolute path of the written HTML file.\n */\nexport async function openDiffInBrowser(patch: string, meta: DiffPageMeta, repoPath: string): Promise<string> {\n const html = await renderDiffPage(patch, meta);\n\n const dir = join(tmpdir(), `cella-diff-${basename(repoPath)}`);\n mkdirSync(dir, { recursive: true });\n const outPath = join(dir, `${meta.filePath.replace(/[^\\w.-]+/g, '-')}.html`);\n\n writeFileSync(outPath, html);\n openWithDefaultApp(outPath);\n return outPath;\n}\n","/**\n * Cleanup utilities for sync CLI v2.\n *\n * Handles worktree cleanup and signal handlers for graceful abort.\n * Uses a temp directory outside the repo so worktree doesn't appear in VSCode.\n */\n\nimport { existsSync, rmSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { basename, join } from 'node:path';\nimport process from 'node:process';\nimport pc from './colors';\nimport { warningMark } from './display';\nimport { listWorktrees, mergeAbort, removeWorktree } from './git';\n\n/**\n * Managed worktree kinds and their system-temp directory prefixes.\n *\n * - `sync`: temporary merge preview worktree. Registered for signal cleanup and\n * removed when the process exits.\n * - `view`: legacy \"upstream view\" worktree that backed VS Code diff links in\n * older CLI versions (before browser diffs). No longer created; the prefix is\n * kept so leftovers from previous versions are removed on the next run.\n */\nconst WORKTREE_PREFIXES = {\n sync: 'cella-sync-',\n view: 'cella-view-',\n} as const;\n\ntype WorktreeKind = keyof typeof WORKTREE_PREFIXES;\n\n/** Build the system-temp worktree path for a kind, keyed by repo name for uniqueness. */\nfunction buildWorktreePath(kind: WorktreeKind, repoPath: string): string {\n return join(tmpdir(), `${WORKTREE_PREFIXES[kind]}${basename(repoPath)}`);\n}\n\n/** Get the temporary sync worktree path in system temp directory (invisible to VSCode). */\nexport function getWorktreePath(repoPath: string): string {\n return buildWorktreePath('sync', repoPath);\n}\n\n/** Track if cleanup is registered */\nlet cleanupRegistered = false;\n\n/** Track current worktree for cleanup */\nlet currentWorktreePath: string | null = null;\nlet currentRepoPath: string | null = null;\n\n/**\n * Register a worktree for cleanup on exit/abort.\n */\nexport function registerWorktree(repoPath: string, worktreePath: string): void {\n currentRepoPath = repoPath;\n currentWorktreePath = worktreePath;\n}\n\n/**\n * Unregister the worktree (call after successful cleanup).\n */\nfunction unregisterWorktree(): void {\n currentRepoPath = null;\n currentWorktreePath = null;\n}\n\n/**\n * Clean up the worktree directory.\n */\nexport async function cleanupWorktree(repoPath: string, worktreePath: string): Promise<void> {\n // Try git worktree remove first\n await removeWorktree(repoPath, worktreePath);\n\n // Force remove directory if it still exists\n if (existsSync(worktreePath)) {\n rmSync(worktreePath, { recursive: true, force: true });\n }\n\n unregisterWorktree();\n}\n\n/**\n * Clean up any leftover worktrees from a previous (interrupted) run, including\n * the legacy upstream-view worktree created by older CLI versions.\n * No-op when no leftovers exist (the common case).\n */\nexport async function cleanupLeftoverWorktrees(repoPath: string): Promise<void> {\n for (const kind of Object.keys(WORKTREE_PREFIXES) as WorktreeKind[]) {\n const worktreePath = buildWorktreePath(kind, repoPath);\n if (existsSync(worktreePath)) {\n await cleanupWorktree(repoPath, worktreePath);\n }\n }\n\n // Also prune any orphaned git worktree references for our managed prefixes.\n const prefixes = Object.values(WORKTREE_PREFIXES);\n const worktrees = await listWorktrees(repoPath);\n for (const wt of worktrees) {\n if (prefixes.some((prefix) => wt.includes(prefix)) && !existsSync(wt)) {\n await removeWorktree(repoPath, wt);\n }\n }\n}\n\n/**\n * Handle abort signal (Ctrl+C).\n */\nasync function handleAbort(signal: string): Promise<void> {\n console.info();\n console.info(`${warningMark} Interrupted (${signal}) - cleaning up...`);\n\n if (currentRepoPath && currentWorktreePath) {\n try {\n // Try to abort any in-progress merge in the worktree\n await mergeAbort(currentWorktreePath);\n } catch {\n // Ignore - merge may not be in progress\n }\n\n try {\n await cleanupWorktree(currentRepoPath, currentWorktreePath);\n console.info(`${pc.green('✓')} no changes were made to your repository.`);\n } catch (error) {\n console.error(\n `${pc.red('✗')} failed to clean up worktree: ${error instanceof Error ? error.message : 'unknown error'}`,\n );\n }\n }\n\n process.exit(1);\n}\n\n/**\n * Register signal handlers for graceful cleanup.\n */\nexport function registerSignalHandlers(): void {\n if (cleanupRegistered) return;\n\n process.on('SIGINT', () => handleAbort('SIGINT'));\n process.on('SIGTERM', () => handleAbort('SIGTERM'));\n\n cleanupRegistered = true;\n}\n","/**\n * Git command helpers for sync CLI v2.\n *\n * Provides typed wrappers around common git operations.\n */\n\nimport { execFile } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readdir, rmdir, unlink } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { getEnvSnapshot } from './env';\nimport { MANIFEST_FILE, readManifestBase, type SyncManifest } from './manifest';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Sanitize text by redacting credentials from URLs.\n * Prevents accidental credential exposure in error messages (CWE-532).\n */\nfunction sanitizeCredentials(text: string): string {\n return text.replace(/https?:\\/\\/[^@\\s]+@/g, (match) => {\n const protocol = match.startsWith('https') ? 'https' : 'http';\n return `${protocol}://***@`;\n });\n}\n\n/** Options for git command execution */\ninterface GitCommandOptions {\n /** Skip editor prompts (for merge commits, etc.) */\n skipEditor?: boolean;\n /** Maximum buffer size for stdout (default: 50MB) */\n maxBuffer?: number;\n /** Ignore command errors (return empty string instead of throwing) */\n ignoreErrors?: boolean;\n /** Additional environment variables for the git command */\n env?: Record<string, string>;\n}\n\n/**\n * Executes a git command and returns trimmed stdout.\n *\n * @param args - Git command arguments (e.g., ['status', '--porcelain'])\n * @param cwd - Working directory for the command\n * @param options - Command execution options\n * @returns Trimmed stdout from the command\n */\nexport async function git(args: string[], cwd: string, options: GitCommandOptions = {}): Promise<string> {\n const env = {\n ...getEnvSnapshot(),\n ...(options.skipEditor ? { GIT_EDITOR: 'true' } : {}),\n ...options.env,\n };\n\n const maxBuffer = options.maxBuffer ?? 50 * 1024 * 1024; // 50MB default\n\n try {\n const { stdout } = await execFileAsync('git', args, { cwd, env, maxBuffer });\n return stdout.trim();\n } catch (error) {\n if (options.ignoreErrors) return '';\n // Sanitize to prevent credential leakage from git remote URLs\n if (error instanceof Error) {\n error.message = sanitizeCredentials(error.message);\n }\n throw error;\n }\n}\n\n/**\n * Get the current branch name.\n */\nexport async function getCurrentBranch(cwd: string): Promise<string> {\n return git(['rev-parse', '--abbrev-ref', 'HEAD'], cwd);\n}\n\n/**\n * Switch to an existing branch.\n */\nexport async function switchBranch(cwd: string, branch: string): Promise<void> {\n await git(['switch', branch], cwd);\n}\n\n/**\n * Create and check out a new branch from a specific start point (branch/ref).\n */\nexport async function createBranchFrom(cwd: string, branch: string, startPoint: string): Promise<void> {\n await git(['switch', '-c', branch, startPoint], cwd);\n}\n\n/**\n * Delete a local branch (force). No-op if it doesn't exist.\n */\nexport async function deleteBranch(cwd: string, branch: string): Promise<void> {\n await git(['branch', '-D', branch], cwd, { ignoreErrors: true });\n}\n\n/**\n * Fast-forward the current branch from its upstream tracking branch.\n * Best-effort: ignores errors (e.g. no origin, offline, or nothing to pull).\n */\nexport async function pullFastForward(cwd: string): Promise<void> {\n await git(['pull', '--ff-only'], cwd, { ignoreErrors: true, skipEditor: true });\n}\n\n/** How the current branch compares to its upstream tracking branch. */\nexport interface UpstreamStatus {\n /** Upstream tracking ref (e.g. `origin/main`), or null when none is configured. */\n upstream: string | null;\n /** Commits the local branch has that its upstream doesn't. */\n ahead: number;\n /** Commits the upstream has that the local branch doesn't. */\n behind: number;\n}\n\n/**\n * Fetch the current branch's upstream, then report how far ahead/behind local is.\n *\n * The fetch is best-effort so an offline/no-remote run still returns whatever is already local.\n * Returns `upstream: null` when the branch has no tracking branch configured (local-only repo).\n */\nexport async function getUpstreamStatus(cwd: string): Promise<UpstreamStatus> {\n const upstream = await git(['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'], cwd, {\n ignoreErrors: true,\n });\n if (!upstream) return { upstream: null, ahead: 0, behind: 0 };\n\n // Refresh the remote-tracking ref so the comparison reflects the remote's latest state.\n const remote = upstream.split('/')[0];\n await git(['fetch', remote], cwd, { ignoreErrors: true, skipEditor: true });\n\n const counts = await git(['rev-list', '--left-right', '--count', `HEAD...${upstream}`], cwd, { ignoreErrors: true });\n const [ahead, behind] = counts.split(/\\s+/).map((n) => Number.parseInt(n, 10) || 0);\n return { upstream, ahead: ahead ?? 0, behind: behind ?? 0 };\n}\n\n/**\n * Push a branch to a remote, setting upstream tracking.\n *\n * `forceWithLease` allows a rewritten branch (see `flattenBranch`) to replace its previously\n * pushed version, while still refusing to overwrite remote commits we haven't seen.\n */\nexport async function pushBranch(\n cwd: string,\n remote: string,\n branch: string,\n options: { forceWithLease?: boolean } = {},\n): Promise<void> {\n await git(['push', '-u', ...(options.forceWithLease ? ['--force-with-lease'] : []), remote, branch], cwd);\n}\n\n/**\n * List merge commits made on the current branch itself: commits with two parents on the\n * first-parent chain from HEAD down to where the branch forked off `baseRef` (newest first).\n *\n * `--first-parent` keeps the walk on the branch's own commits, so merge commits that merely\n * exist inside a merged-in history (e.g. upstream's internal merges) don't count.\n */\nexport async function listBranchMergeCommits(cwd: string, baseRef: string): Promise<string[]> {\n const out = await git(['rev-list', '--merges', '--first-parent', `${baseRef}..HEAD`], cwd, { ignoreErrors: true });\n return out ? out.split('\\n').filter(Boolean) : [];\n}\n\n/**\n * Rewrite the current branch as one commit with `message`, parented on the point where the\n * branch forked off `baseRef`. The tree (content) is kept exactly as-is — only the commit\n * graph changes, so the branch's diff against the base is untouched.\n *\n * Companion to `commitSquash` for commits that already happened: a manual `git commit` during\n * a sync merge records a two-parent merge commit, which makes the PR list the upstream\n * branch's entire (unshared) history. Flattening restores the single-commit shape.\n */\nexport async function flattenBranch(cwd: string, baseRef: string, message: string): Promise<void> {\n const parent = await getMergeBase(cwd, baseRef, 'HEAD');\n const tree = await git(['rev-parse', 'HEAD^{tree}'], cwd);\n const commit = await git(['commit-tree', tree, '-p', parent, '-m', message], cwd);\n await git(['reset', '--hard', commit], cwd);\n}\n\n/**\n * Commit the staged changes as a single-parent commit, discarding any in-progress merge state.\n *\n * A normal commit with `MERGE_HEAD` present records a two-parent merge commit. Because the fork\n * doesn't share pushed ancestry with upstream (the local `git replace` graft that makes merges\n * incremental is never pushed), such a merge commit makes the PR list the upstream branch's\n * entire history. Removing the merge state first collapses the staged delta into one clean\n * commit, so the PR shows a single commit with the incremental diff.\n */\nexport async function commitSquash(cwd: string, message: string): Promise<void> {\n for (const file of ['MERGE_HEAD', 'MERGE_MSG', 'MERGE_MODE']) {\n const path = join(cwd, '.git', file);\n if (existsSync(path)) await unlink(path);\n }\n await git(['commit', '-m', message], cwd, { skipEditor: true });\n}\n\n/**\n * Stage every change in the working tree (`git add -A`), including untracked and deleted files.\n */\nexport async function stageAll(cwd: string): Promise<void> {\n await git(['add', '-A'], cwd);\n}\n\n/**\n * Whether a merge is currently in progress (MERGE_HEAD present).\n */\nexport function mergeInProgress(cwd: string): boolean {\n return existsSync(join(cwd, '.git', 'MERGE_HEAD'));\n}\n\n/**\n * Get the abbreviated (short) SHA for a ref.\n */\nexport async function getShortSha(cwd: string, ref: string): Promise<string> {\n return git(['rev-parse', '--short', ref], cwd);\n}\n\n/**\n * Count uncommitted working tree entries using porcelain status.\n */\nexport async function getWorkingTreeChangeCount(cwd: string): Promise<number> {\n const status = await git(['status', '--porcelain'], cwd);\n if (!status) return 0;\n return status.split('\\n').filter(Boolean).length;\n}\n\n/**\n * Check if a remote exists.\n */\nasync function remoteExists(cwd: string, remoteName: string): Promise<boolean> {\n const remotes = await git(['remote'], cwd);\n return remotes.split('\\n').includes(remoteName);\n}\n\n/**\n * Get the URL of a remote.\n */\nexport async function getRemoteUrl(cwd: string, remoteName: string): Promise<string | null> {\n try {\n const url = await git(['remote', 'get-url', remoteName], cwd, { ignoreErrors: true });\n return url.trim() || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Add a remote if it doesn't exist.\n */\nexport async function ensureRemote(cwd: string, remoteName: string, url: string): Promise<void> {\n if (await remoteExists(cwd, remoteName)) {\n // Update URL if remote exists\n await git(['remote', 'set-url', remoteName, url], cwd);\n } else {\n await git(['remote', 'add', remoteName, url], cwd);\n }\n}\n\n/**\n * Fetch from a remote.\n */\nexport async function fetch(cwd: string, remoteName: string): Promise<void> {\n await git(['fetch', remoteName], cwd);\n}\n\n/**\n * Fetch upstream tags into a remote-scoped namespace (`refs/<remoteName>/tags/*`)\n * instead of the local `refs/tags/*`. This keeps cella's release tags from\n * colliding with the fork's own release tags (forks run their own release-please).\n * `--no-tags` prevents git from also writing them into `refs/tags/*`.\n */\nexport async function fetchUpstreamTags(cwd: string, remoteName: string): Promise<void> {\n await git(['fetch', remoteName, '--no-tags', `+refs/tags/*:refs/${remoteName}/tags/*`], cwd);\n}\n\n/**\n * Resolve the latest upstream release tag (semver-sorted `v*` tag) from the\n * remote-scoped tag namespace. Excludes non-template tags (e.g. `create-cella-v*`).\n * Returns the short tag name and its full ref, or null when no release exists.\n */\nexport async function resolveLatestReleaseTag(\n cwd: string,\n remoteName: string,\n): Promise<{ tag: string; ref: string } | null> {\n const prefix = `refs/${remoteName}/tags/`;\n const output = await git(['for-each-ref', '--sort=-version:refname', '--format=%(refname)', prefix], cwd, {\n ignoreErrors: true,\n });\n if (!output) return null;\n for (const line of output.split('\\n')) {\n const ref = line.trim();\n if (!ref) continue;\n const tag = ref.slice(prefix.length);\n // Template release tags look like 'v0.5.0'; skip component tags like 'create-cella-v*'.\n if (/^v\\d/.test(tag)) return { tag, ref };\n }\n return null;\n}\n\n/**\n * Get the latest commit info from a ref.\n */\nexport async function getCommitInfo(\n cwd: string,\n ref: string,\n): Promise<{ hash: string; message: string; date: string }> {\n const format = '%H%n%s%n%ar'; // hash, subject, relative date\n const output = await git(['log', '-1', `--format=${format}`, ref], cwd);\n const [hash, message, date] = output.split('\\n');\n return { hash, message, date };\n}\n\n/**\n * Count the number of commits between two refs.\n * Returns the number of commits in `toRef` that are not in `fromRef`.\n */\nexport async function countCommitsBetween(cwd: string, fromRef: string, toRef: string): Promise<number> {\n const output = await git(['rev-list', '--count', `${fromRef}..${toRef}`], cwd);\n return Number.parseInt(output.trim(), 10) || 0;\n}\n\n/** Commit metadata for a single log entry */\nexport interface CommitRangeEntry {\n hash: string;\n message: string;\n date: string;\n}\n\n/**\n * List commits in a ref range.\n *\n * By default this returns commits oldest-first to match GitHub compare ordering.\n * Supports skip+limit pagination so callers can show only the most recent N commits\n * without fetching the entire range.\n */\nexport async function listCommitsBetween(\n cwd: string,\n fromRef: string,\n toRef: string,\n options: {\n oldestFirst?: boolean;\n skip?: number;\n limit?: number;\n } = {},\n): Promise<CommitRangeEntry[]> {\n const { oldestFirst = true, skip = 0, limit } = options;\n const args = ['log', '--format=%H%x1f%s%x1f%ar'];\n\n if (oldestFirst) args.push('--reverse');\n args.push(`${fromRef}..${toRef}`);\n\n const output = await git(args, cwd, { ignoreErrors: true });\n if (!output) return [];\n\n const commits: CommitRangeEntry[] = [];\n for (const line of output.split('\\n')) {\n if (!line) continue;\n const [hash, message, date] = line.split('\\x1f');\n if (!hash || !message || !date) continue;\n commits.push({ hash, message, date });\n }\n\n const normalizedSkip = Math.max(0, skip);\n const normalizedLimit = typeof limit === 'number' && limit > 0 ? limit : undefined;\n\n if (normalizedSkip === 0 && normalizedLimit === undefined) {\n return commits;\n }\n\n const start = Math.min(normalizedSkip, commits.length);\n const end = normalizedLimit === undefined ? commits.length : Math.min(start + normalizedLimit, commits.length);\n return commits.slice(start, end);\n}\n\n/**\n * File change info with date and commit hash.\n */\ninterface FileChangeInfo {\n date: string;\n hash: string;\n /** Unix epoch seconds of the change, for sorting */\n timestamp: number;\n}\n\n/**\n * Get the relative date and commit hash of the last change for all files in a range.\n * Returns a map of filePath -> { date, hash }.\n * Uses a single git command to get all info efficiently.\n */\nexport async function getFileChangeInfo(\n cwd: string,\n fromRef: string,\n toRef: string,\n): Promise<Map<string, FileChangeInfo>> {\n const info = new Map<string, FileChangeInfo>();\n\n try {\n // Get all commits in range with their files, dates, and hashes\n // Format: hash, epoch timestamp, relative date, then list of files changed\n const output = await git(['log', '--name-only', '--format=%h %ct %ar', `${fromRef}..${toRef}`], cwd, {\n ignoreErrors: true,\n });\n\n if (!output.trim()) return info;\n\n const lines = output.split('\\n');\n let currentHash = '';\n let currentDate = '';\n let currentTimestamp = 0;\n\n for (const line of lines) {\n if (!line) continue;\n\n // Check if this is a hash+timestamp+date line (starts with short hash)\n const match = line.match(/^([a-f0-9]{7,})\\s+(\\d+)\\s+(.+)$/);\n if (match) {\n currentHash = match[1];\n currentTimestamp = Number(match[2]);\n currentDate = match[3];\n } else if (currentHash && currentDate && !info.has(line)) {\n // This is a file path - only set if not already set (we want most recent)\n info.set(line, { date: currentDate, hash: currentHash, timestamp: currentTimestamp });\n }\n }\n } catch {\n // Ignore errors, return empty map\n }\n\n return info;\n}\n\n/**\n * Check if the working tree is clean (no uncommitted changes).\n */\nexport async function isClean(cwd: string): Promise<boolean> {\n const status = await git(['status', '--porcelain'], cwd);\n return !status;\n}\n\n/**\n * Throw if the working tree has uncommitted changes.\n * `subject` labels the repo in the error (e.g. 'working directory', 'fork').\n */\nexport async function assertClean(cwd: string, subject = 'working directory'): Promise<void> {\n if (!(await isClean(cwd))) {\n throw new Error(`${subject} has uncommitted changes. please commit or stash before syncing.`);\n }\n}\n\n/**\n * Create a worktree from a commit (detached HEAD).\n * Uses --detach to avoid \"branch already checked out\" errors.\n */\nexport async function createWorktree(cwd: string, worktreePath: string, commitRef: string): Promise<void> {\n await git(['worktree', 'add', '--detach', worktreePath, commitRef], cwd);\n}\n\n/**\n * Remove a worktree.\n */\nexport async function removeWorktree(cwd: string, worktreePath: string): Promise<void> {\n await git(['worktree', 'remove', worktreePath, '--force'], cwd, { ignoreErrors: true });\n await git(['worktree', 'prune'], cwd, { ignoreErrors: true });\n}\n\n/**\n * List existing worktrees.\n */\nexport async function listWorktrees(cwd: string): Promise<string[]> {\n const output = await git(['worktree', 'list', '--porcelain'], cwd);\n const lines = output.split('\\n');\n const paths: string[] = [];\n for (const line of lines) {\n if (line.startsWith('worktree ')) {\n paths.push(line.slice(9));\n }\n }\n return paths;\n}\n\n/**\n * Perform a merge in the current directory.\n * Always uses --no-ff to prevent fast-forward, ensuring HEAD stays in place\n * and MERGE_HEAD is created for proper merge state tracking.\n */\nexport async function merge(\n cwd: string,\n ref: string,\n options: { noCommit?: boolean; noEdit?: boolean } = {},\n): Promise<{ success: boolean; conflicts: string[] }> {\n const args = ['merge', '--no-ff', ref];\n if (options.noCommit) args.push('--no-commit');\n if (options.noEdit) args.push('--no-edit');\n\n try {\n await git(args, cwd, { skipEditor: true });\n return { success: true, conflicts: [] };\n } catch (error) {\n // Check for conflicts\n const conflicts = await getConflictedFiles(cwd);\n if (conflicts.length > 0) {\n return { success: false, conflicts };\n }\n throw error;\n }\n}\n\n/**\n * Get list of files with merge conflicts.\n */\nexport async function getConflictedFiles(cwd: string): Promise<string[]> {\n const output = await git(['diff', '--name-only', '--diff-filter=U'], cwd, { ignoreErrors: true });\n if (!output) return [];\n return output.split('\\n').filter(Boolean);\n}\n\n/**\n * Abort an in-progress merge.\n */\nexport async function mergeAbort(cwd: string): Promise<void> {\n await git(['merge', '--abort'], cwd, { ignoreErrors: true });\n}\n\n/**\n * Check if a file exists at a ref.\n */\nexport async function fileExistsAtRef(cwd: string, ref: string, filePath: string): Promise<boolean> {\n const result = await git(['ls-tree', '--name-only', ref, '--', filePath], cwd, { ignoreErrors: true });\n return result !== '';\n}\n\n/**\n * Checkout a file from a specific ref.\n * Used to restore files from upstream that don't exist in fork.\n */\nexport async function checkoutFromRef(cwd: string, ref: string, filePath: string): Promise<void> {\n await git(['checkout', ref, '--', filePath], cwd);\n}\n\n/**\n * Restore a path from a ref into the working tree only, leaving the index untouched.\n * Useful when we want adopted changes to remain unstaged for review.\n */\nexport async function restoreWorktreeFromRef(cwd: string, ref: string, filePath: string): Promise<void> {\n await git(['restore', `--source=${ref}`, '--worktree', '--', filePath], cwd);\n}\n\n/**\n * Get the merge base between two refs.\n */\nexport async function getMergeBase(cwd: string, ref1: string, ref2: string): Promise<string> {\n return git(['merge-base', ref1, ref2], cwd);\n}\n\n/** File change status codes from git diff-tree */\ntype FileChangeStatus = 'A' | 'D' | 'M' | 'T' | 'R';\n\n/** File change info from git diff-tree */\ninterface FileChange {\n status: FileChangeStatus;\n baseHash: string | null;\n targetHash: string | null;\n /** For renames: the original path (before rename) */\n oldPath?: string;\n /** For renames: the new path (after rename) */\n newPath?: string;\n}\n\n/**\n * Get files changed between two refs using diff-tree.\n * Returns a map of filePath -> FileChange\n *\n * This is much faster than checking each file individually.\n * Status codes: A=added, D=deleted, M=modified, T=type-changed, R=renamed\n *\n * Uses -M90% to detect renames with 90% similarity threshold.\n * For renames, the map key is the NEW path, with oldPath stored in the value.\n */\nexport async function getFileChanges(\n cwd: string,\n baseRef: string,\n targetRef: string,\n): Promise<Map<string, FileChange>> {\n // Use diff-tree with -M90% to detect renames (90% similarity threshold)\n // Format for non-renames: :oldmode newmode oldhash newhash status\\tpath\n // Format for renames: :oldmode newmode oldhash newhash Rxx\\toldpath\\tnewpath\n const output = await git(['diff-tree', '-r', '-M90%', '--no-commit-id', baseRef, targetRef], cwd, {\n ignoreErrors: true,\n });\n\n const changes = new Map<string, FileChange>();\n\n if (!output) return changes;\n\n for (const line of output.split('\\n')) {\n if (!line) continue;\n\n // Check for rename first (Rxx status with two paths)\n // Format: :100644 100644 abc123... def456... R100 oldpath\\tnewpath\n // Note: space after Rxx, then tab between old and new paths\n const renameMatch = line.match(/^:\\d+ \\d+ ([a-f0-9]+) ([a-f0-9]+) R\\d*\\s+(.+)\\t(.+)$/);\n if (renameMatch) {\n const [, baseHash, targetHash, oldPath, newPath] = renameMatch;\n changes.set(newPath, {\n status: 'R',\n baseHash: baseHash === '0'.repeat(40) ? null : baseHash,\n targetHash: targetHash === '0'.repeat(40) ? null : targetHash,\n oldPath,\n newPath,\n });\n continue;\n }\n\n // Parse non-rename: :100644 100644 abc123... def456... M\\tpath/to/file\n const match = line.match(/^:\\d+ \\d+ ([a-f0-9]+) ([a-f0-9]+) ([ADMT])\\t(.+)$/);\n if (match) {\n const [, baseHash, targetHash, status, filePath] = match;\n changes.set(filePath, {\n status: status as 'A' | 'D' | 'M' | 'T',\n baseHash: baseHash === '0'.repeat(40) ? null : baseHash,\n targetHash: targetHash === '0'.repeat(40) ? null : targetHash,\n });\n }\n }\n\n return changes;\n}\n\n/**\n * Get all file hashes at a ref using ls-tree (batch operation).\n * Returns a Map of filePath -> hash for quick lookups.\n */\nexport async function getFileHashesAtRef(cwd: string, ref: string): Promise<Map<string, string>> {\n const output = await git(['ls-tree', '-r', ref], cwd);\n const hashes = new Map<string, string>();\n\n if (!output) return hashes;\n\n for (const line of output.split('\\n')) {\n if (!line) continue;\n // Parse: <mode> <type> <hash>\\t<path>\n const match = line.match(/^\\d+ \\w+ ([a-f0-9]+)\\t(.+)$/);\n if (match) {\n const [, hash, filePath] = match;\n hashes.set(filePath, hash);\n }\n }\n\n return hashes;\n}\n\n/**\n * Restore a file to HEAD version (our version during merge).\n * Updates both index and worktree to match HEAD.\n *\n * Uses `git checkout HEAD --` instead of `git restore --source=HEAD` because\n * `git restore` fails on unmerged (conflicted) paths during a merge, while\n * `git checkout HEAD --` resolves them by taking HEAD's version.\n */\nexport async function restoreToHead(cwd: string, filePath: string): Promise<void> {\n await git(['checkout', 'HEAD', '--', filePath], cwd);\n}\n\n/**\n * Batch restore multiple files to HEAD version in a single git command.\n * Much faster than calling restoreToHead for each file individually.\n * Reduces IDE file watcher events by completing all restores at once.\n *\n * Uses `git checkout HEAD --` instead of `git restore --source=HEAD` because\n * `git restore` fails on unmerged (conflicted) paths during a merge, while\n * `git checkout HEAD --` resolves them by taking HEAD's version.\n */\nexport async function batchRestoreToHead(cwd: string, filePaths: string[]): Promise<void> {\n if (filePaths.length === 0) return;\n await git(['checkout', 'HEAD', '--', ...filePaths], cwd);\n}\n\n/**\n * Remove a file from index with tracked delete (git rm).\n * Records a deletion in the merge result.\n */\nexport async function gitRm(cwd: string, filePath: string): Promise<void> {\n await git(['rm', '-f', '--', filePath], cwd, { ignoreErrors: true });\n}\n\n/**\n * Batch remove multiple files from index with tracked delete.\n * Much faster than calling gitRm for each file individually.\n */\nexport async function batchGitRm(cwd: string, filePaths: string[]): Promise<void> {\n if (filePaths.length === 0) return;\n await git(['rm', '-f', '--', ...filePaths], cwd, { ignoreErrors: true });\n}\n\n/**\n * Get files staged as new additions in the index (diff-filter=A vs HEAD).\n * These are files that don't exist at HEAD but were brought in by a merge.\n */\nexport async function getStagedNewFiles(cwd: string): Promise<string[]> {\n const output = await git(['diff', '--cached', '--name-only', '--diff-filter=A'], cwd, { ignoreErrors: true });\n return output ? output.split('\\n').filter(Boolean) : [];\n}\n\n/**\n * Remove files from the index only (--cached), leaving the working tree untouched.\n * Useful for cleaning up files staged by a merge that shouldn't be committed.\n */\nexport async function batchUnstageFiles(cwd: string, filePaths: string[]): Promise<void> {\n if (filePaths.length === 0) return;\n await git(['rm', '--cached', '-f', '--', ...filePaths], cwd, { ignoreErrors: true });\n}\n\n/**\n * Move/rename a file using git mv.\n * Creates parent directories if needed and preserves git history.\n */\nexport async function gitMv(cwd: string, oldPath: string, newPath: string): Promise<void> {\n // Ensure parent directory exists for new path\n const newDir = dirname(join(cwd, newPath));\n await mkdir(newDir, { recursive: true });\n\n await git(['mv', '-f', oldPath, newPath], cwd);\n}\n\n/**\n * Check if a file exists in the worktree filesystem.\n */\nexport async function fileExistsInWorktree(cwd: string, filePath: string): Promise<boolean> {\n return existsSync(join(cwd, filePath));\n}\n\n/**\n * Remove a file from the worktree filesystem if it exists.\n * Used to clean up files that git rm may not have removed (e.g., after squash merge).\n */\nexport async function removeFileFromWorktree(cwd: string, filePath: string): Promise<void> {\n const fullPath = join(cwd, filePath);\n try {\n await unlink(fullPath);\n // Try to clean up empty parent directories\n await cleanupEmptyParentDirs(cwd, dirname(filePath));\n } catch {\n // File doesn't exist or can't be removed - ignore\n }\n}\n\n/**\n * Fully remove a file: tracked delete from the index (git rm) plus filesystem removal\n * for cases git rm leaves behind (e.g. during a merge), including empty parent dirs.\n */\nexport async function removeFileFully(cwd: string, filePath: string): Promise<void> {\n await gitRm(cwd, filePath);\n await removeFileFromWorktree(cwd, filePath);\n}\n\n/**\n * Recursively remove empty parent directories up to (but not including) the root.\n * Stops when encountering a non-empty directory or the root.\n */\nasync function cleanupEmptyParentDirs(cwd: string, relativePath: string): Promise<void> {\n if (!relativePath || relativePath === '.') return;\n\n const fullPath = join(cwd, relativePath);\n try {\n const entries = await readdir(fullPath);\n if (entries.length === 0) {\n await rmdir(fullPath);\n // Recurse to parent\n await cleanupEmptyParentDirs(cwd, dirname(relativePath));\n }\n } catch {\n // Directory doesn't exist, not empty, or can't be removed - stop\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Sync ref tracking & merge-base recovery\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Store the upstream commit hash after a successful sync.\n * Used to recover correct merge-base when squash strategy creates single-parent commits.\n *\n * Also records the fork HEAD at store time as `refs/cella/last-sync-head`. The last-sync\n * ref is written while the merge is still staged (before the user commits), so it cannot be\n * trusted on its own: if the user runs `git merge --abort`, HEAD never advances and the ref\n * is left pointing at an upstream commit that was never actually integrated. Recording HEAD\n * lets `getEffectiveMergeBase` detect that an aborted/uncommitted merge produced a stale ref.\n */\nexport async function storeLastSyncRef(cwd: string, upstreamHash: string): Promise<void> {\n await git(['update-ref', 'refs/cella/last-sync', upstreamHash], cwd);\n const head = await git(['rev-parse', 'HEAD'], cwd, { ignoreErrors: true });\n if (head) {\n await git(['update-ref', 'refs/cella/last-sync-head', head], cwd);\n }\n}\n\n/** Stage a single path (git add). Best-effort — never throws. */\nexport async function stagePath(cwd: string, path: string): Promise<void> {\n await git(['add', '--', path], cwd, { ignoreErrors: true });\n}\n\n/**\n * Get the stored last-sync upstream ref.\n * Returns null if no previous sync has been recorded.\n */\nexport async function getStoredSyncRef(cwd: string): Promise<string | null> {\n const ref = await git(['rev-parse', 'refs/cella/last-sync'], cwd, { ignoreErrors: true });\n return ref || null;\n}\n\n/**\n * Get the fork HEAD that was recorded when the last-sync ref was stored.\n * Returns null if no HEAD was recorded.\n */\nexport async function getStoredSyncHead(cwd: string): Promise<string | null> {\n const ref = await git(['rev-parse', 'refs/cella/last-sync-head'], cwd, { ignoreErrors: true });\n return ref || null;\n}\n\n/**\n * Read the sync manifest committed at a specific ref.\n *\n * This intentionally reads from git, not the working tree: a staged/aborted sync can leave the\n * worktree manifest ahead of the committed trunk, and that must not validate a sync point.\n */\nexport async function readManifestAtRef(cwd: string, ref: string): Promise<SyncManifest | null> {\n const raw = await git(['show', `${ref}:${MANIFEST_FILE}`], cwd, { ignoreErrors: true });\n if (!raw) return null;\n\n try {\n const parsed = JSON.parse(raw) as SyncManifest;\n const commit = parsed?.upstream?.commit;\n if (typeof commit !== 'string' || !/^[0-9a-f]{40}$/i.test(commit)) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\n/** The upstream base commit SHA from the manifest committed at `ref`, or null. */\nexport async function readManifestBaseAtRef(cwd: string, ref: string): Promise<string | null> {\n const manifest = await readManifestAtRef(cwd, ref);\n return manifest ? manifest.upstream.commit.toLowerCase() : null;\n}\n\n/**\n * Read the `version` field of the root `package.json` committed at a ref.\n * Returns null when the file is absent or unparsable.\n */\nexport async function readPackageVersionAtRef(cwd: string, ref: string): Promise<string | null> {\n const raw = await git(['show', `${ref}:package.json`], cwd, { ignoreErrors: true });\n if (!raw) return null;\n\n try {\n const version = (JSON.parse(raw) as { version?: unknown }).version;\n return typeof version === 'string' && version ? version : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Check whether a commit object is present in the local object store.\n */\nasync function commitObjectExists(cwd: string, sha: string): Promise<boolean> {\n try {\n await git(['cat-file', '-e', `${sha}^{commit}`], cwd);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get the root (parentless) commit of a ref's history. A create-cella scaffold has a\n * single rootless \"Initial commit\" whose tree is a frozen snapshot of the upstream\n * template at scaffold time. Returns null when no root is found.\n */\nasync function getRootCommit(cwd: string, ref: string): Promise<string | null> {\n const out = await git(['rev-list', '--max-parents=0', ref], cwd, { ignoreErrors: true });\n const roots = out.split('\\n').filter(Boolean);\n return roots.length > 0 ? roots[roots.length - 1] : null;\n}\n\n/** Max upstream commits scored when inferring a scaffold base by tree similarity. */\nconst SCAFFOLD_CANDIDATE_LIMIT = 400;\n\n/** Concurrent diff-tree scoring calls during scaffold-base inference. */\nconst SCAFFOLD_SCORE_CONCURRENCY = 10;\n\n/**\n * Reject an inferred scaffold base when more than this fraction of the root snapshot's\n * paths differ from the best-matching upstream commit. The template cleaner rewrites a\n * fixed handful of files and deselected optional modules remove a few folders, so a real\n * scaffold stays far below this; a hand-rolled repo blows past it.\n */\nconst SCAFFOLD_MATCH_MAX_DIFF_RATIO = 0.3;\n\n/**\n * Infer the upstream commit a scaffold was created from, by tree similarity.\n *\n * A create-cella scaffold's root commit is a frozen snapshot of the upstream tree at\n * scaffold time: the template cleaner only rewrites a handful of files (project name,\n * ports, changelog) and drops deselected module folders, so the vast majority of paths\n * stay byte-identical to exactly one upstream commit. Diff the root tree against recent\n * upstream commits and take the closest match — no provenance file needed.\n *\n * Candidates are bounded to upstream commits no newer than the root commit (plus a\n * clock-skew margin): the scaffold cannot come from a commit that didn't exist yet.\n * Neighboring candidates can tie when the commits between them only touch files the\n * scaffold rewrote anyway (upstream release commits do exactly this) — either tie is a\n * correct base for the 3-way merge, and newest wins.\n *\n * Returns null when no candidate matches convincingly (see SCAFFOLD_MATCH_MAX_DIFF_RATIO).\n */\nasync function inferScaffoldBase(cwd: string, headRef: string, upstreamRef: string): Promise<string | null> {\n const root = await getRootCommit(cwd, headRef);\n if (!root) return null;\n\n const rootDate = await git(['show', '-s', '--format=%cI', root], cwd, { ignoreErrors: true });\n if (!rootDate) return null;\n // A day of margin absorbs clock skew between the scaffolding machine and upstream committers.\n const before = new Date(new Date(rootDate).getTime() + 24 * 60 * 60 * 1000).toISOString();\n\n const revList = await git(\n ['rev-list', `--max-count=${SCAFFOLD_CANDIDATE_LIMIT}`, `--before=${before}`, upstreamRef],\n cwd,\n { ignoreErrors: true },\n );\n const candidates = revList.split('\\n').filter(Boolean);\n if (candidates.length === 0) return null;\n\n const totalPaths = (await git(['ls-tree', '-r', '--name-only', root], cwd)).split('\\n').filter(Boolean).length;\n if (totalPaths === 0) return null;\n\n // Score = differing paths between candidate and root snapshot. rev-list is newest-first\n // and strict `<` keeps the first (newest) candidate on ties.\n let best: { sha: string; diff: number } | null = null;\n outer: for (let i = 0; i < candidates.length; i += SCAFFOLD_SCORE_CONCURRENCY) {\n const chunk = candidates.slice(i, i + SCAFFOLD_SCORE_CONCURRENCY);\n const scores = await Promise.all(\n chunk.map(async (sha) => {\n try {\n const out = await git(['diff-tree', '-r', '--name-only', sha, root], cwd);\n return { sha, diff: out ? out.split('\\n').length : 0 };\n } catch {\n return { sha, diff: Number.POSITIVE_INFINITY };\n }\n }),\n );\n for (const score of scores) {\n if (!best || score.diff < best.diff) best = score;\n if (best.diff === 0) break outer; // byte-identical snapshot — cannot do better\n }\n }\n\n if (!best || best.diff / totalPaths > SCAFFOLD_MATCH_MAX_DIFF_RATIO) return null;\n return best.sha;\n}\n\n/**\n * Read the scaffold provenance trailer from the fork's root commit message.\n *\n * create-cella stamps `Cella-Base: <sha>` on the initial commit, recording the exact\n * upstream commit the scaffold snapshot was taken from. Riding in commit history, it\n * travels with push/clone — unlike a local ref — and needs no file in the worktree.\n */\nasync function readRootTrailerBase(cwd: string, headRef: string): Promise<string | null> {\n const root = await getRootCommit(cwd, headRef);\n if (!root) return null;\n const message = await git(['show', '-s', '--format=%B', root], cwd, { ignoreErrors: true });\n const match = message.match(/^cella-base:\\s*([0-9a-f]{40})$/im);\n return match ? match[1].toLowerCase() : null;\n}\n\n/**\n * Whether the repository is a shallow clone (created with `git clone --depth`, or otherwise\n * carrying a `.git/shallow` graft). Shallow history is truncated below the graft point, so the\n * real common ancestor with upstream is absent: `git merge-base` finds nothing even when one\n * exists in the full history, and the 3-way file analysis walks an incomplete commit graph.\n */\nexport async function isShallowRepository(cwd: string): Promise<boolean> {\n const out = await git(['rev-parse', '--is-shallow-repository'], cwd, { ignoreErrors: true });\n return out === 'true';\n}\n\n/**\n * Restore full history on a shallow clone by fetching from its own origin, so merge-base and the\n * 3-way analysis see the real commit graph. Grafting cannot recover this case (the intermediate\n * commits are genuinely missing, not just disconnected), so the history is deepened for real.\n *\n * Throws an actionable error when the history cannot be restored (e.g. no reachable origin),\n * because sync cannot run correctly against truncated history.\n */\nexport async function unshallowRepository(cwd: string): Promise<void> {\n try {\n await git(['fetch', '--unshallow'], cwd, { skipEditor: true });\n } catch (error) {\n const detail = error instanceof Error ? `\\n\\n${error.message}` : '';\n throw new Error(\n 'this is a shallow clone and its full history could not be restored automatically.\\n' +\n 'Sync needs the complete history to find the common ancestor with upstream. Restore it with:\\n\\n' +\n ' git fetch --unshallow\\n\\n' +\n `then re-run sync.${detail}`,\n );\n }\n}\n\n/**\n * Ensure a native git merge-base exists between the fork and upstream.\n *\n * A create-cella scaffold — or a fork whose upstream squashed its history — has unrelated\n * histories, so `git merge-base` finds nothing and every sync fails at the very first step.\n * This bootstraps ancestry non-destructively:\n * 0. If the repo is a shallow clone, restore its full history first — the real ancestor is\n * truncated away, so no graft can recover it; deepening the history brings it back.\n * 1. If a native merge-base already exists, do nothing (the common case).\n * 2. Otherwise resolve the logical base commit: sources are tried in order and the first\n * one whose commit actually exists after the upstream fetch wins — the sync-point\n * record (`refs/cella/last-sync` ref, then committed/worktree `cella/cella.manifest.json`),\n * then the scaffold origin (the root commit's `Cella-Base:` trailer, then tree-similarity\n * inference as reseed fallback for scaffolds whose trailer is absent or stale).\n * 3. Graft the fork's root commit onto that base with `git replace --graft`, so every native\n * git operation (merge-base and the 3-way merge itself) sees correct ancestry. The replace\n * ref is local-only and never pushed, so the fork's own published history stays clean.\n *\n * Throws an actionable error when no valid base can be determined.\n */\nexport async function ensureSyncBase(cwd: string, headRef: string, upstreamRef: string): Promise<void> {\n // A shallow clone has its history truncated below the graft point, so the real common ancestor\n // is absent and merge-base finds nothing. Restore the full history first: this is not unrelated\n // history to graft over, it is real history to bring back.\n if (await isShallowRepository(cwd)) {\n await unshallowRepository(cwd);\n }\n\n // Native ancestry already present — nothing to bootstrap.\n const nativeBase = await git(['merge-base', headRef, upstreamRef], cwd, { ignoreErrors: true });\n if (nativeBase) return;\n\n const sources: Array<() => Promise<string | null>> = [\n () => getStoredSyncRef(cwd),\n () => readManifestBaseAtRef(cwd, headRef),\n () => readManifestBase(cwd),\n () => readRootTrailerBase(cwd, headRef),\n () => inferScaffoldBase(cwd, headRef, upstreamRef),\n ];\n\n let baseSha: string | null = null;\n for (const source of sources) {\n const sha = await source();\n if (sha && (await commitObjectExists(cwd, sha))) {\n baseSha = sha;\n break;\n }\n }\n if (!baseSha) {\n throw new Error(\n `no common ancestor between the fork and '${upstreamRef}', and no sync base could be determined.\\n\\n` +\n 'This fork has unrelated history with upstream — typical for a create-cella scaffold, or after\\n' +\n 'upstream squashed its history — and no recorded or inferable base commit exists after fetching\\n' +\n 'upstream. Seed it manually with the upstream commit the fork was created from, then re-run sync:\\n\\n' +\n ' git update-ref refs/cella/last-sync <upstream-sha>\\n',\n );\n }\n\n const root = await getRootCommit(cwd, headRef);\n if (!root) throw new Error(\"could not determine the fork's root commit to bootstrap sync ancestry\");\n\n // Graft the fork root onto the base (idempotent via -f) so native git sees the ancestry.\n await git(['replace', '-f', '--graft', root, baseSha], cwd);\n\n // Record the base as the last-sync ref so future runs and the squash strategy stay consistent.\n await git(['update-ref', 'refs/cella/last-sync', baseSha], cwd);\n}\n\n/**\n * Check if one commit is an ancestor of another.\n */\nexport async function isAncestor(cwd: string, ancestor: string, descendant: string): Promise<boolean> {\n try {\n await git(['merge-base', '--is-ancestor', ancestor, descendant], cwd);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Legacy sync point for forks that last synced before the manifest was committed: the local\n * last-sync ref, guarded against aborted merges. The ref is written while the merge is still\n * staged; if the user ran `git merge --abort` instead of committing, HEAD never advanced past\n * the recorded sync HEAD and the upstream commits were never integrated, so the ref is discarded.\n */\nasync function getLegacySyncRef(cwd: string, headRef: string): Promise<string | null> {\n const storedRef = await getStoredSyncRef(cwd);\n if (!storedRef) return null;\n\n const storedHead = await getStoredSyncHead(cwd);\n if (storedHead) {\n const currentHead = await git(['rev-parse', headRef], cwd, { ignoreErrors: true });\n if (currentHead && currentHead === storedHead) return null;\n }\n\n return storedRef;\n}\n\n/**\n * Get the effective merge-base, preferring the recorded sync point when it's more recent.\n * This handles stale merge-base caused by previous squash syncs (single-parent commits\n * don't update git's merge-base graph).\n *\n * The manifest committed at `headRef` is the authoritative record: the sync engine stages it\n * inside every applied sync, so it lands iff the sync commit lands. That makes it immune to\n * aborted merges (never committed) and available on fresh clones and other machines (it\n * travels with the repo, unlike local refs). The local last-sync ref is only consulted as a\n * fallback for forks whose last sync predates the manifest.\n *\n * @returns The effective base commit, whether git's base was stale, and the recorded sync point\n */\nexport async function getEffectiveMergeBase(\n cwd: string,\n headRef: string,\n upstreamRef: string,\n): Promise<{ base: string; isStale: boolean; storedRef: string | null }> {\n const gitBase = await getMergeBase(cwd, headRef, upstreamRef);\n\n const recorded = (await readManifestBaseAtRef(cwd, headRef)) ?? (await getLegacySyncRef(cwd, headRef));\n if (!recorded) {\n return { base: gitBase, isStale: false, storedRef: null };\n }\n\n // Only prefer the recorded sync point when it is actually newer than git's own answer.\n const recordedIsNewer = await isAncestor(cwd, gitBase, recorded);\n if (recordedIsNewer && recorded !== gitBase) {\n return { base: recorded, isStale: true, storedRef: recorded };\n }\n\n return { base: gitBase, isStale: false, storedRef: recorded };\n}\n\n/**\n * Run `fn` with a temporary local graft that makes `baseSha` an ancestor of `headRef`, so\n * native git operations — merge-base resolution and the 3-way merge itself — see the recorded\n * sync point instead of a stale historical ancestor.\n *\n * Squash syncs advance the recorded sync point (manifest + `refs/cella/last-sync`) without\n * advancing git's commit graph, so a plain `git merge` replays every upstream change since the\n * last true merge ancestor: hunks the fork already integrated (or deliberately resolved away)\n * re-apply as clean auto-merges or re-conflict on every sync. The graft adds `baseSha` as an\n * extra parent of the `headRef` commit via `git replace --graft`; replace refs are local-only\n * and the ref is deleted right after `fn`, so nothing ever leaks into pushed history.\n *\n * Runs `fn` without grafting when the graft is unnecessary or unsafe:\n * - `baseSha` is already an ancestor of `headRef` (git's own merge-base is not stale), or\n * - a replacement object already exists for the `headRef` commit (never clobber, e.g. the\n * scaffold root graft from {@link ensureSyncBase} when the root commit is HEAD).\n */\nexport async function withTemporarySyncBaseGraft<T>(\n cwd: string,\n headRef: string,\n baseSha: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const headSha = await git(['rev-parse', headRef], cwd, { ignoreErrors: true });\n if (!headSha || !(await commitObjectExists(cwd, baseSha))) return fn();\n\n // Native ancestry already covers the base — nothing to graft.\n if (await isAncestor(cwd, baseSha, headSha)) return fn();\n\n // Never clobber an existing replacement object for this commit.\n const existingReplacement = await git(['replace', '-l', headSha], cwd, { ignoreErrors: true });\n if (existingReplacement) return fn();\n\n const parentsRaw = await git(['log', '-1', '--format=%P', headSha], cwd, { ignoreErrors: true });\n const parents = parentsRaw ? parentsRaw.split(/\\s+/) : [];\n\n await git(['replace', '-f', '--graft', headSha, ...parents, baseSha], cwd);\n try {\n return await fn();\n } finally {\n await git(['replace', '-d', headSha], cwd, { ignoreErrors: true });\n }\n}\n","/**\n * Cella sync manifest.\n *\n * A committed record of the last upstream sync point, living in the fork's `cella/` folder as\n * `cella/cella.manifest.json`. It serves two purposes:\n * 1. Machine: `upstream.commit` is the bootstrap seed `ensureSyncBase` uses to reconstruct\n * the merge-base on a clone that has no local `refs/cella/last-sync` (fresh clone, CI, a\n * second maintainer). Committed, so it travels with the repo — unlike the local ref.\n * 2. Human: records the upstream repo, tracking mode, release/commit and a GitHub link, so\n * each sync PR shows exactly which upstream point you moved to.\n *\n * Written and staged by the sync engine on every applied sync, so it stays in lockstep with\n * `refs/cella/last-sync` and rides along in the sync commit.\n */\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\n/** Committed manifest path, relative to the fork repo root. */\nexport const MANIFEST_FILE = 'cella/cella.manifest.json';\n\n/** The last upstream sync point recorded in {@link MANIFEST_FILE}. */\nexport interface SyncManifest {\n upstream: {\n /** GitHub slug of the upstream repo, e.g. 'cellajs/cella'. */\n repo?: string;\n /** Tracking mode at sync time. */\n track?: 'release' | 'branch';\n /** Integrated upstream commit SHA — the merge-base bootstrap seed. */\n commit: string;\n /** Release tag when tracking releases, else null. */\n release?: string | null;\n /** Human-readable link to the commit or release on GitHub. */\n url?: string;\n /** UTC timestamp of the sync (ISO 8601). */\n syncedAt?: string;\n };\n}\n\n/** Read and validate the manifest. Returns null when absent or malformed. */\nexport async function readSyncManifest(cwd: string): Promise<SyncManifest | null> {\n try {\n const parsed = JSON.parse(await readFile(join(cwd, MANIFEST_FILE), 'utf8')) as SyncManifest;\n const commit = parsed?.upstream?.commit;\n if (typeof commit !== 'string' || !/^[0-9a-f]{40}$/i.test(commit)) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\n/**\n * Return the recorded upstream base commit SHA, or null.\n * Bootstrap seed for {@link ensureSyncBase} when no local `refs/cella/last-sync` exists.\n */\nexport async function readManifestBase(cwd: string): Promise<string | null> {\n const manifest = await readSyncManifest(cwd);\n return manifest ? manifest.upstream.commit.toLowerCase() : null;\n}\n\n/** Write the manifest as pretty JSON with a trailing newline. */\nexport async function writeSyncManifest(cwd: string, manifest: SyncManifest): Promise<void> {\n const manifestPath = join(cwd, MANIFEST_FILE);\n // Ensure the cella/ folder exists (a fresh fork may not have it yet on first sync).\n await mkdir(dirname(manifestPath), { recursive: true });\n await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`, 'utf8');\n}\n","/**\n * Direction-agnostic ref analyzer for sync CLI.\n *\n * Compares a \"local\" ref against an \"incoming\" ref using a shared merge-base,\n * classifying every changed file (identical / ahead / local / drifted / behind /\n * diverged / pinned / ignored / deleted / renamed). It works purely on git\n * plumbing (ls-tree, diff-tree, log) against refs — never the working tree.\n *\n * Both directions reuse it:\n * - sync (merge-engine): local = fork HEAD, incoming = upstream\n * - contributions: local = cella branch, incoming = fork branch\n *\n * The result fields `existsInFork`/`existsInUpstream` map to local/incoming\n * respectively (named for the sync direction, reused as-is for contributions).\n */\n\nimport type { AnalyzedFile, FileStatus } from '../config/types';\nimport { getFileChangeInfo, getFileChanges, getFileHashesAtRef } from '../utils/git';\n\n/** Predicates and options that steer classification (direction-specific). */\nexport interface AnalyzePredicates {\n /** True if the file is inside owned/ignored territory (never synced). */\n isIgnored: (path: string) => boolean;\n /** True if the file is pinned (local wins on conflict). */\n isPinned: (path: string) => boolean;\n /** Treat drifted files as behind (overwrite local with incoming). */\n hard?: boolean;\n}\n\n/** Progress callback type - receives a message string. */\ntype ProgressCallback = (message: string) => void;\n\n/**\n * Analyze files between a local and an incoming ref using a merge-base.\n *\n * @param repoPath - Repo where all refs are reachable (git ops run here)\n * @param localRef - The \"ours\" ref (e.g. fork HEAD, or cella branch)\n * @param incomingRef - The \"theirs\" ref (e.g. upstream, or fork branch)\n * @param mergeBaseRef - Common ancestor ref used for 3-way comparison\n * @param predicates - Direction-specific ignore/pin/hard behavior\n */\nexport async function analyzeRefs(\n repoPath: string,\n localRef: string,\n incomingRef: string,\n mergeBaseRef: string,\n predicates: AnalyzePredicates,\n onProgress?: ProgressCallback,\n): Promise<AnalyzedFile[]> {\n onProgress?.('collecting file hashes (batch)...');\n\n // Batch get all file hashes at each ref (one git call per ref)\n const [forkHashes, upstreamHashes, baseHashes] = await Promise.all([\n getFileHashesAtRef(repoPath, localRef),\n getFileHashesAtRef(repoPath, incomingRef),\n getFileHashesAtRef(repoPath, mergeBaseRef),\n ]);\n\n // Get only files that changed between base and incoming (includes renames with -M90%)\n const upstreamChanges = await getFileChanges(repoPath, mergeBaseRef, incomingRef);\n // Get only files that changed between base and local\n const forkChanges = await getFileChanges(repoPath, mergeBaseRef, localRef);\n\n // Build a map of old paths that were renamed in incoming (oldPath -> newPath)\n const upstreamRenames = new Map<string, string>();\n for (const [newPath, change] of upstreamChanges) {\n if (change.status === 'R' && change.oldPath) {\n upstreamRenames.set(change.oldPath, newPath);\n }\n }\n\n // Combined set of all files (for completeness, but we'll only analyze non-identical)\n // Also include old paths from renames to properly track them\n const allFiles = new Set([...forkHashes.keys(), ...upstreamHashes.keys(), ...upstreamRenames.keys()]);\n\n // Files that actually need analysis (changed somewhere)\n const changedFiles = new Set([...upstreamChanges.keys(), ...forkChanges.keys(), ...upstreamRenames.keys()]);\n\n // Content hashes present anywhere in incoming — O(1) rename-source lookups below.\n const upstreamHashSet = new Set(upstreamHashes.values());\n\n onProgress?.(\n `analyzing ${changedFiles.size} changed files (${allFiles.size - changedFiles.size} identical skipped)...`,\n );\n\n const analyzedFiles: AnalyzedFile[] = [];\n // Track old paths that have been handled as part of a rename\n const handledOldPaths = new Set<string>();\n let processed = 0;\n\n for (const filePath of allFiles) {\n // Skip old paths that were already handled as part of a rename\n if (handledOldPaths.has(filePath)) continue;\n\n const inFork = forkHashes.has(filePath);\n const inUpstream = upstreamHashes.has(filePath);\n\n const fileIsIgnored = predicates.isIgnored(filePath);\n const fileIsPinned = predicates.isPinned(filePath);\n\n // Check if this file is the NEW path of an incoming rename\n const upstreamChange = upstreamChanges.get(filePath);\n const isUpstreamRename = upstreamChange?.status === 'R' && upstreamChange.oldPath;\n\n // Check if this file is the OLD path that was renamed in incoming\n const renamedToPath = upstreamRenames.get(filePath);\n\n // Fast path: if file didn't change anywhere, it's identical\n if (!changedFiles.has(filePath) && inFork && inUpstream) {\n analyzedFiles.push({\n path: filePath,\n status: 'identical',\n isIgnored: fileIsIgnored,\n isPinned: fileIsPinned,\n existsInFork: true,\n existsInUpstream: true,\n });\n continue;\n }\n\n processed++;\n if (processed % 100 === 0) {\n onProgress?.(`analyzing ${processed}/${changedFiles.size} changed files...`);\n }\n\n const forkHash = forkHashes.get(filePath) ?? null;\n const upstreamHash = upstreamHashes.get(filePath) ?? null;\n const baseHash = baseHashes.get(filePath) ?? null;\n\n // Determine status\n let status: FileStatus;\n let renamedFrom: string | undefined;\n\n // Handle incoming renames\n if (isUpstreamRename && upstreamChange.oldPath) {\n const oldPath = upstreamChange.oldPath;\n const oldPathInFork = forkHashes.has(oldPath);\n const forkOldHash = forkHashes.get(oldPath) ?? null;\n const baseOldHash = baseHashes.get(oldPath) ?? null;\n\n // Mark the old path as handled so we don't process it separately\n handledOldPaths.add(oldPath);\n\n // Check if local modified the old file\n const forkModifiedOld = forkOldHash !== baseOldHash;\n\n // Check both old and new paths for pinned/ignored status.\n // When a directory is renamed (e.g., config/ → shared/), the local\n // pinned list may still reference the old path.\n const oldPathPinned = predicates.isPinned(oldPath);\n\n if (fileIsPinned || oldPathPinned || predicates.isIgnored(oldPath)) {\n // Pinned or ignored - keep local's version at the new path\n status = 'pinned';\n } else if (!oldPathInFork) {\n // Old path doesn't exist locally (already deleted or moved it)\n // Treat as normal behind - let git's merge handle it\n status = 'behind';\n } else if (forkModifiedOld) {\n // Local modified the old file - this is a diverged situation\n // Let git's merge handle the conflict naturally\n status = 'diverged';\n renamedFrom = oldPath;\n } else {\n // Local has unmodified old file - this is a clean rename to apply\n status = 'renamed';\n renamedFrom = oldPath;\n }\n\n analyzedFiles.push({\n path: filePath,\n status,\n isIgnored: fileIsIgnored,\n isPinned: fileIsPinned,\n existsInFork: inFork,\n existsInUpstream: true,\n renamedFrom,\n });\n continue;\n }\n\n // Skip old paths that were renamed - they'll be handled via the new path\n if (renamedToPath) {\n // This is an old path that incoming renamed - skip it, handled above\n handledOldPaths.add(filePath);\n continue;\n }\n\n if (fileIsIgnored) {\n status = 'ignored';\n } else if (!inFork && inUpstream) {\n // File is missing locally but present in incoming. Distinguish a genuinely new\n // incoming file from a file the local side deliberately deleted, by consulting\n // the merge-base (the symmetric `inFork && !inUpstream` branch does the same):\n // - pinned: local owns the path, keep it removed.\n // - existed at base and incoming hasn't touched it since (upstreamHash === baseHash):\n // the absence is a deliberate local deletion — keep it deleted instead of\n // re-adding it as if incoming introduced a new file (which resurfaces every sync).\n // - otherwise (never in base = truly new, or incoming modified a file the local side\n // deleted = delete/modify): surface incoming's version.\n const locallyDeleted = baseHash !== null && upstreamHash === baseHash;\n status = fileIsPinned || locallyDeleted ? 'deleted' : 'behind';\n } else if (inFork && !inUpstream) {\n // File exists locally but not in incoming\n if (baseHash !== null) {\n // File was in base, incoming deleted it - sync deletion unless pinned\n status = fileIsPinned ? 'ahead' : 'behind';\n } else {\n // Local file (never existed in merge-base). If its exact content exists at a\n // different path in incoming, it is likely the source of a rename we couldn't\n // detect due to a squash merge-base — treat as behind so the rename applies.\n // (This file is absent from incoming, so any hash match is at another path.)\n status = forkHash && upstreamHashSet.has(forkHash) ? 'behind' : 'local';\n }\n } else if (forkHash === upstreamHash) {\n // Identical\n status = 'identical';\n } else {\n // Both exist but different\n const forkChanged = forkHash !== baseHash;\n const upstreamChanged = upstreamHash !== baseHash;\n\n if (forkChanged && upstreamChanged) {\n // Both changed - diverged or pinned conflict\n status = fileIsPinned ? 'pinned' : 'diverged';\n } else if (forkChanged && !upstreamChanged) {\n // Only local changed\n // --hard mode: treat drifted as behind (overwrite with incoming)\n status = fileIsPinned ? 'ahead' : predicates.hard ? 'behind' : 'drifted';\n } else if (!forkChanged && upstreamChanged) {\n // Only incoming changed\n status = 'behind';\n } else {\n // Base is different but local and incoming are same relative to base\n status = 'identical';\n }\n }\n\n analyzedFiles.push({\n path: filePath,\n status,\n isIgnored: fileIsIgnored,\n isPinned: fileIsPinned,\n existsInFork: inFork,\n existsInUpstream: inUpstream,\n });\n }\n\n return analyzedFiles;\n}\n\n/**\n * Enrich analyzed files with change dates and commit hashes.\n *\n * Mutates each non-identical file in place: local-side dates for ahead/drifted,\n * incoming-side dates for behind, and both sides for diverged/pinned.\n *\n * @param repoPath - Repo where the refs are reachable\n * @param files - Files to enrich (mutated in place)\n * @param mergeBaseRef - Common ancestor ref\n * @param localRef - The \"ours\" ref\n * @param incomingRef - The \"theirs\" ref\n */\nexport async function enrichChangeInfo(\n repoPath: string,\n files: AnalyzedFile[],\n mergeBaseRef: string,\n localRef: string,\n incomingRef: string,\n): Promise<void> {\n const forkInfo = await getFileChangeInfo(repoPath, mergeBaseRef, localRef);\n const upstreamInfo = await getFileChangeInfo(repoPath, mergeBaseRef, incomingRef);\n\n for (const file of files) {\n if (file.status === 'identical') continue;\n\n if (file.status === 'ahead' || file.status === 'drifted') {\n const info = forkInfo.get(file.path);\n if (info) {\n file.changedAt = info.date;\n file.changedTs = info.timestamp;\n file.changedCommit = info.hash;\n }\n } else if (file.status === 'behind') {\n const info = upstreamInfo.get(file.path);\n if (info) {\n file.changedAt = info.date;\n file.changedTs = info.timestamp;\n file.changedCommit = info.hash;\n }\n } else if (file.status === 'diverged' || file.status === 'pinned') {\n // For diverged/pinned: store both local and incoming info\n const forkFileInfo = forkInfo.get(file.path);\n const upstreamFileInfo = upstreamInfo.get(file.path);\n if (forkFileInfo) {\n file.changedAt = forkFileInfo.date;\n file.changedTs = forkFileInfo.timestamp;\n file.changedCommit = forkFileInfo.hash;\n }\n if (upstreamFileInfo) {\n file.upstreamChangedAt = upstreamFileInfo.date;\n file.upstreamChangedTs = upstreamFileInfo.timestamp;\n file.upstreamCommit = upstreamFileInfo.hash;\n }\n }\n }\n}\n","/**\n * Merge Engine for sync CLI v2.\n *\n * Two modes:\n * - Analyze (dry run): Uses worktree to preview changes without affecting fork\n * - Sync: Performs real merge directly in fork for full IDE support\n *\n * Sync mode approach:\n * 1. Start real merge in fork (git merge --no-commit)\n * 2. Apply resolutions directly (pinned→ours, ignored→rm, diverged→git's merge)\n * 3. Leave fork in merge state - conflicts have markers for IDE 3-way merge\n *\n * Key principle: Fork stays in real merge state for IDE conflict resolution.\n */\n\nimport type { AnalysisSummary, AnalyzedFile, MergeResult, RuntimeConfig } from '../config/types';\nimport { cleanupLeftoverWorktrees, cleanupWorktree, getWorktreePath, registerWorktree } from '../utils/cleanup';\nimport { DEFAULT_UPSTREAM_REMOTE, resolveUpstream } from '../utils/config';\nimport { formatFetchedUpstreamDetail, formatMergeInProgressDetail } from '../utils/display';\nimport {\n batchGitRm,\n batchRestoreToHead,\n batchUnstageFiles,\n type CommitRangeEntry,\n checkoutFromRef,\n countCommitsBetween,\n createWorktree,\n ensureRemote,\n ensureSyncBase,\n fetch,\n fetchUpstreamTags,\n fileExistsAtRef,\n fileExistsInWorktree,\n getCommitInfo,\n getConflictedFiles,\n getCurrentBranch,\n getEffectiveMergeBase,\n getMergeBase,\n getShortSha,\n getStagedNewFiles,\n getUpstreamStatus,\n getWorkingTreeChangeCount,\n gitMv,\n listCommitsBetween,\n merge,\n mergeAbort,\n removeFileFromWorktree,\n removeFileFully,\n resolveLatestReleaseTag,\n restoreToHead,\n stagePath,\n storeLastSyncRef,\n withTemporarySyncBaseGraft,\n} from '../utils/git';\nimport { isManagedFile } from '../utils/managed-files';\nimport { MANIFEST_FILE, type SyncManifest, writeSyncManifest } from '../utils/manifest';\nimport { isIgnored, isPinnedForSync } from '../utils/overrides';\nimport { type AnalyzePredicates, analyzeRefs, enrichChangeInfo } from './analyze-core';\n\n/** Progress callback type - receives message and optional detail for sub-line */\ntype ProgressCallback = (message: string, detail?: string) => void;\n\n/** Step completion callback - marks a step as done with optional detail */\ntype StepCallback = (label: string, detail?: string) => void;\n\n/**\n * Convert a git remote URL to a GitHub base URL.\n * Supports both SSH (git@github.com:org/repo.git) and HTTPS formats.\n */\nfunction getGitHubBaseUrl(remoteUrl: string): string | null {\n // SSH format: git@github.com:cellajs/cella.git\n const sshMatch = remoteUrl.match(/git@github\\.com:([^/]+)\\/([^.]+)(?:\\.git)?$/);\n if (sshMatch) {\n return `https://github.com/${sshMatch[1]}/${sshMatch[2]}`;\n }\n\n // HTTPS format: https://github.com/cellajs/cella.git\n const httpsMatch = remoteUrl.match(/https:\\/\\/github\\.com\\/([^/]+)\\/([^/.]+)(?:\\.git)?$/);\n if (httpsMatch) {\n return `https://github.com/${httpsMatch[1]}/${httpsMatch[2]}`;\n }\n\n return null;\n}\n\n/** Build analyzer predicates for the sync direction (local = fork, incoming = upstream). */\nfunction syncPredicates(config: RuntimeConfig): AnalyzePredicates {\n return {\n isIgnored: (path) => isIgnored(path, config),\n isPinned: (path) => isPinnedForSync(path, config, config.unpinned),\n hard: config.hard,\n };\n}\n\n/**\n * Apply merge directly to fork with pre-analysis.\n *\n * Strategy: analyze BEFORE merge (uses git refs only, invisible to IDE),\n * then merge + immediate batch resolution to minimize working tree flickering.\n *\n * 1. Pre-analyze using git refs (no working tree changes)\n * 2. Collect batch resolution plan (which files to restore/remove)\n * 3. Start real merge in fork (git merge --no-commit)\n * 4. Immediately batch-restore pinned/ignored files (single git command)\n * 5. Apply remaining individual resolutions\n * 6. Leave fork in merge state for IDE 3-way conflict resolution\n */\nasync function applyDirectMerge(\n forkPath: string,\n upstreamRef: string,\n mergeBaseRef: string,\n config: RuntimeConfig,\n onProgress?: ProgressCallback,\n): Promise<{\n remainingConflicts: string[];\n analyzedFiles: AnalyzedFile[];\n autoMergedFiles: string[];\n}> {\n // Phase 1: Pre-analyze using git refs (invisible to IDE).\n // analyzeRefs only uses git plumbing (ls-tree, diff-tree) on refs,\n // not the working tree, so results are identical before or after merge.\n onProgress?.('analyzing files...');\n const analyzedFiles = await analyzeRefs(\n forkPath,\n 'HEAD',\n upstreamRef,\n mergeBaseRef,\n syncPredicates(config),\n onProgress,\n );\n\n // Phase 2: Collect batch resolution plan for immediate post-merge application.\n // These files will be restored to HEAD in a single git command right after merge,\n // preventing the IDE from seeing upstream changes to pinned/ignored files.\n const batchRestorePaths: string[] = [];\n const batchRemovePaths: string[] = [];\n\n for (const file of analyzedFiles) {\n const { path: filePath, status, isPinned: pinned, isIgnored: ignored, existsInFork } = file;\n if (status === 'identical' || status === 'ahead') continue;\n\n if (ignored && existsInFork) {\n batchRestorePaths.push(filePath);\n } else if (ignored && !existsInFork) {\n batchRemovePaths.push(filePath);\n } else if (pinned && !file.renamedFrom && existsInFork) {\n batchRestorePaths.push(filePath);\n } else if (pinned && !file.renamedFrom && !existsInFork) {\n // Pinned file doesn't exist in fork — remove from merge to keep fork's state (deleted)\n batchRemovePaths.push(filePath);\n }\n }\n\n // Phase 3: Start real merge in fork. Left staged with MERGE_HEAD intact so git and the IDE\n // treat it as a real in-progress merge (3-way conflict view, `git merge --abort` works).\n // The finishing rerun squashes the commit to a single parent (`commitSquash`) — upstream\n // ancestry is tracked via the manifest, never via a pushed two-parent merge commit.\n // The temporary graft makes the merge 3-way against the recorded sync point instead of\n // git's own (squash-stale) merge-base — without it, upstream hunks already integrated by\n // previous syncs re-apply or re-conflict on every run.\n onProgress?.('starting merge in fork...');\n await withTemporarySyncBaseGraft(forkPath, 'HEAD', mergeBaseRef, () =>\n merge(forkPath, upstreamRef, { noCommit: true, noEdit: true }),\n );\n\n // Phase 4: Immediately batch-restore pinned/ignored files.\n // Single git command restores all files at once, minimizing the window\n // where the IDE sees upstream changes to protected files.\n if (batchRestorePaths.length > 0) {\n onProgress?.(`batch restoring ${batchRestorePaths.length} pinned/ignored files...`);\n await batchRestoreToHead(forkPath, batchRestorePaths);\n }\n if (batchRemovePaths.length > 0) {\n onProgress?.(`batch removing ${batchRemovePaths.length} ignored files...`);\n await batchGitRm(forkPath, batchRemovePaths);\n for (const filePath of batchRemovePaths) {\n await removeFileFromWorktree(forkPath, filePath);\n }\n }\n\n // Phase 5: Apply remaining individual resolutions.\n // Pinned/ignored already handled in batch above — skip them here.\n for (const file of analyzedFiles) {\n const { path: filePath, status, isPinned: pinned, isIgnored: ignored, existsInFork } = file;\n\n if (status === 'identical' || status === 'ahead') {\n continue;\n }\n\n // Skip files already handled in batch\n if (ignored) continue;\n if (pinned && !file.renamedFrom) continue;\n\n if (pinned && file.renamedFrom) {\n // Renamed file where old path was pinned — accept the rename (new path)\n // but keep fork's content from the old path\n const oldPathExists = await fileExistsInWorktree(forkPath, file.renamedFrom);\n if (oldPathExists) {\n onProgress?.(`→ ${file.renamedFrom} → ${filePath}: moving fork content (pinned rename)`);\n try {\n await gitMv(forkPath, file.renamedFrom, filePath);\n } catch {\n // git mv failed — copy content manually\n await removeFileFully(forkPath, file.renamedFrom);\n // Checkout upstream's new path first, then restore fork content\n await checkoutFromRef(forkPath, 'HEAD', file.renamedFrom).catch(() => {});\n }\n } else {\n // Old path already gone — restore from HEAD at old path via git show\n onProgress?.(`→ ${filePath}: keeping fork content (pinned rename, old path removed)`);\n await restoreToHead(forkPath, filePath);\n }\n continue;\n }\n\n if (status === 'diverged') {\n // Let git's merge result stand - trust the merge\n onProgress?.(`→ ${filePath}: using git merge result (diverged)`);\n continue;\n }\n\n if (status === 'behind') {\n // File only in upstream or upstream has newer version\n if (!existsInFork) {\n // Upstream added new file\n onProgress?.(`→ ${filePath}: adding from upstream (new file)`);\n await checkoutFromRef(forkPath, upstreamRef, filePath);\n } else if (!file.existsInUpstream) {\n // Upstream deleted file - remove from fork (including leftovers after squash merge)\n onProgress?.(`→ ${filePath}: removing (deleted in upstream)`);\n await removeFileFully(forkPath, filePath);\n } else {\n // Both exist, only upstream changed - accept upstream version explicitly.\n // This resolves false conflicts from stale merge-base (previous squash syncs).\n onProgress?.(`→ ${filePath}: accepting upstream (behind)`);\n await checkoutFromRef(forkPath, upstreamRef, filePath);\n }\n continue;\n }\n\n if (status === 'deleted') {\n await removeFileFully(forkPath, filePath);\n continue;\n }\n\n if (status === 'renamed' && file.renamedFrom) {\n // Upstream renamed a file - apply as git mv to preserve history\n const oldPath = file.renamedFrom;\n const oldPathExists = await fileExistsInWorktree(forkPath, oldPath);\n const newPathExists = await fileExistsInWorktree(forkPath, filePath);\n\n if (oldPathExists && !newPathExists) {\n // Old exists, new doesn't - use git mv to move the file, preserving history\n onProgress?.(`→ ${oldPath} → ${filePath}: moving (renamed in upstream)`);\n try {\n await gitMv(forkPath, oldPath, filePath);\n } catch {\n // git mv failed (possibly due to merge state) - fall back to manual approach\n await removeFileFully(forkPath, oldPath);\n await checkoutFromRef(forkPath, upstreamRef, filePath);\n }\n } else if (oldPathExists && newPathExists) {\n // Both exist (merge already staged the new file, but old still in worktree)\n // Remove old and ensure new has correct content\n onProgress?.(`→ ${oldPath} → ${filePath}: completing rename (removing old)`);\n await removeFileFully(forkPath, oldPath);\n await checkoutFromRef(forkPath, upstreamRef, filePath);\n } else {\n // Rename already applied (or neither path exists) - ensure new path has upstream content\n onProgress?.(`→ ${filePath}: updating from upstream (renamed)`);\n await checkoutFromRef(forkPath, upstreamRef, filePath);\n }\n }\n }\n\n // Handle remaining git conflicts: auto-resolve only ignored/pinned (fork wins);\n // everything else keeps its markers for IDE 3-way resolution.\n const gitConflicts = await getConflictedFiles(forkPath);\n for (const filePath of gitConflicts) {\n const isProtected = isIgnored(filePath, config) || isPinnedForSync(filePath, config, config.unpinned);\n if (!isProtected) continue;\n\n if (await fileExistsAtRef(forkPath, 'HEAD', filePath)) {\n onProgress?.(`→ ${filePath}: keeping fork (protected conflict)`);\n await restoreToHead(forkPath, filePath);\n } else {\n onProgress?.(`→ ${filePath}: removing (protected conflict, not in fork)`);\n await removeFileFully(forkPath, filePath);\n }\n }\n\n // Get remaining conflicts (these have markers for IDE)\n const remainingConflicts = await getConflictedFiles(forkPath);\n const remainingConflictSet = new Set(remainingConflicts);\n const autoMergedFiles = analyzedFiles\n .filter((file) => file.status === 'diverged' && !remainingConflictSet.has(file.path))\n .map((file) => file.path);\n\n // Phase 6: Safety net — clean up any ignored files still staged after merge.\n // During a merge, batchGitRm can silently fail on newly-added files, leaving\n // them as \"Added in index, Deleted from working tree\" (AD status). This catches\n // any ignored files that slipped through the earlier resolution phases.\n const stagedNewFiles = await getStagedNewFiles(forkPath);\n const staleIgnoredFiles = stagedNewFiles.filter((f) => isIgnored(f, config));\n if (staleIgnoredFiles.length > 0) {\n onProgress?.(`cleaning up ${staleIgnoredFiles.length} ignored files still in index...`);\n await batchUnstageFiles(forkPath, staleIgnoredFiles);\n for (const filePath of staleIgnoredFiles) {\n await removeFileFromWorktree(forkPath, filePath);\n }\n }\n\n return { remainingConflicts, analyzedFiles, autoMergedFiles };\n}\n\n/**\n * Calculate summary from analyzed files.\n */\nfunction calculateSummary(files: AnalyzedFile[]): AnalysisSummary {\n const summary: AnalysisSummary = {\n managed: 0,\n identical: 0,\n ahead: 0,\n local: 0,\n drifted: 0,\n behind: 0,\n diverged: 0,\n pinned: 0,\n ignored: 0,\n deleted: 0,\n renamed: 0,\n total: files.length,\n };\n\n for (const file of files) {\n if (file.status !== 'identical' && isManagedFile(file.path)) {\n summary.managed++;\n continue;\n }\n\n summary[file.status]++;\n }\n\n return summary;\n}\n\n/**\n * Upstream context resolved once per run and shared by both engine modes.\n */\ninterface UpstreamContext {\n /** Concrete upstream ref merged from (branch tip or release-tag ref) */\n upstreamRef: string;\n /** Release tag when tracking releases */\n releaseTag?: string;\n /** Effective merge-base used for the 3-way analysis */\n mergeBase: string;\n /** Upstream GitHub URL base for commit links */\n upstreamGitHubUrl?: string;\n /** Upstream HEAD commit info */\n upstreamCommit: { hash: string; message: string; date: string };\n /** Commits included in this sync range (oldest-first) */\n upstreamCommits: CommitRangeEntry[];\n}\n\nfunction formatLocalCheckoutDetail(\n forkPath: string,\n branch: string,\n headSha: string,\n changeCount: number,\n upstream: { upstream: string | null; ahead: number; behind: number },\n): string {\n const tracking = upstream.upstream\n ? `, tracking ${upstream.upstream} (${upstream.ahead} ahead, ${upstream.behind} behind)`\n : ', no tracking branch';\n const workingTree =\n changeCount === 0\n ? ' working tree clean'\n : ` ${changeCount} uncommitted change${changeCount === 1 ? '' : 's'} in working tree, not included in analysis`;\n\n return [`${forkPath}`, ` ${branch} @ ${headSha}${tracking}`, workingTree].join('\\n');\n}\n\n/**\n * Resolve everything both modes need from upstream: remote setup, the concrete\n * ref to merge (branch tip or latest release tag), sync ancestry bootstrap,\n * effective merge-base, and commit info for progress output.\n */\nasync function prepareUpstream(\n config: RuntimeConfig,\n onProgress?: ProgressCallback,\n onStep?: StepCallback,\n): Promise<UpstreamContext> {\n const { forkPath } = config;\n\n onProgress?.('checking local checkout...');\n const [branch, headSha, changeCount, upstreamStatus] = await Promise.all([\n getCurrentBranch(forkPath),\n getShortSha(forkPath, 'HEAD'),\n getWorkingTreeChangeCount(forkPath),\n getUpstreamStatus(forkPath),\n ]);\n onStep?.('local checkout', formatLocalCheckoutDetail(forkPath, branch, headSha, changeCount, upstreamStatus));\n\n // Setup upstream remote\n onProgress?.('setting up upstream remote...');\n const { track: configTrack, branchRef } = resolveUpstream(config.settings);\n const remoteName = DEFAULT_UPSTREAM_REMOTE;\n // A per-run --track flag (config.track) overrides the configured tracking mode.\n const track = config.track ?? configTrack;\n await ensureRemote(forkPath, remoteName, config.settings.upstreamUrl);\n\n // Fetch upstream (branches, plus release tags into a fork-safe namespace).\n onProgress?.(`fetching upstream (${remoteName})...`);\n await fetch(forkPath, remoteName);\n\n // Resolve the concrete ref to merge from. Release tracking (default) syncs to the\n // latest published release tag; branch tracking follows the upstream branch tip.\n let upstreamRef = branchRef;\n let releaseTag: string | undefined;\n if (track === 'release') {\n await fetchUpstreamTags(forkPath, remoteName);\n const latest = await resolveLatestReleaseTag(forkPath, remoteName);\n if (!latest) {\n throw new Error(\n `no upstream releases (v*) found on '${remoteName}'. Set upstreamTrack: 'branch' to follow ${branchRef}, ` +\n `or check that ${config.settings.upstreamUrl} publishes release tags.`,\n );\n }\n upstreamRef = latest.ref;\n releaseTag = latest.tag;\n }\n\n // Expose the resolved ref to downstream steps (packages/analyze read config.upstreamRef\n // after the engine runs). The static fallback set at CLI parse time is the branch tip.\n config.upstreamRef = upstreamRef;\n onStep?.('remote configured', `${releaseTag ?? upstreamRef} → ${config.settings.upstreamUrl}`);\n\n // Bootstrap sync ancestry for forks with unrelated history (create-cella scaffold or an\n // upstream history squash). No-op once a native merge-base exists. Runs after fetch so the\n // base commit object is present, and after upstreamRef is finalized so release tags resolve.\n onProgress?.('checking sync base...');\n await ensureSyncBase(forkPath, 'HEAD', upstreamRef);\n\n const upstreamGitHubUrl = getGitHubBaseUrl(config.settings.upstreamUrl) ?? undefined;\n\n // Get effective merge base (handles stale base from previous squash syncs).\n // --hard and --unpinned use the natural merge-base instead, resurfacing the\n // full upstream history so previously-hidden drift/pins reappear consistently.\n const aggressive = config.hard === true || config.unpinned === true;\n const mergeBase = aggressive\n ? await getMergeBase(forkPath, 'HEAD', upstreamRef)\n : (await getEffectiveMergeBase(forkPath, 'HEAD', upstreamRef)).base;\n\n // Get upstream commit info and count commits since merge-base\n const upstreamCommit = await getCommitInfo(forkPath, upstreamRef);\n const commitCount = await countCommitsBetween(forkPath, mergeBase, upstreamRef);\n const commitListMax = 50;\n const commitSkip = commitCount > commitListMax ? commitCount - commitListMax : 0;\n const upstreamCommits =\n commitCount > 0\n ? await listCommitsBetween(forkPath, mergeBase, upstreamRef, {\n oldestFirst: true,\n skip: commitSkip,\n limit: commitListMax,\n })\n : [];\n\n onStep?.('fetched upstream', formatFetchedUpstreamDetail(commitCount, upstreamCommits, upstreamGitHubUrl));\n\n return { upstreamRef, releaseTag, mergeBase, upstreamGitHubUrl, upstreamCommit, upstreamCommits };\n}\n\n/** MergeResult fields shared by both engine modes. */\nfunction resultMeta(config: RuntimeConfig, ctx: UpstreamContext) {\n return {\n upstreamBranch: config.settings.upstreamBranch ?? 'main',\n upstreamRef: ctx.upstreamRef,\n upstreamTag: ctx.releaseTag,\n upstreamGitHubUrl: ctx.upstreamGitHubUrl,\n upstreamCommit: ctx.upstreamCommit,\n upstreamCommits: ctx.upstreamCommits,\n };\n}\n\n/**\n * SYNC MODE: merge, analyze, and resolve directly in the fork, then record the\n * sync point (local ref + committed manifest) and leave the merge staged.\n */\nasync function runSyncMerge(\n config: RuntimeConfig,\n ctx: UpstreamContext,\n onProgress?: ProgressCallback,\n onStep?: StepCallback,\n): Promise<MergeResult> {\n const { forkPath } = config;\n const { upstreamRef, releaseTag, mergeBase, upstreamGitHubUrl, upstreamCommit } = ctx;\n\n const { remainingConflicts, analyzedFiles, autoMergedFiles } = await applyDirectMerge(\n forkPath,\n upstreamRef,\n mergeBase,\n config,\n onProgress,\n );\n\n const summary = calculateSummary(analyzedFiles);\n const synced = analyzedFiles.filter((file) => ['behind', 'diverged', 'renamed'].includes(file.status)).length;\n\n // Count total resolved changes (includes ignored/pinned resolutions)\n const totalResolved = analyzedFiles.filter((file) =>\n ['behind', 'diverged', 'renamed', 'ignored', 'pinned'].includes(file.status),\n ).length;\n\n // Record the upstream sync point in lockstep: the local `refs/cella/last-sync` ref plus\n // the committed `cella/cella.manifest.json` (staged so it rides in the sync commit and travels\n // with the repo for fresh-clone bootstrap).\n const syncManifest: SyncManifest = {\n upstream: {\n repo: upstreamGitHubUrl ? upstreamGitHubUrl.replace('https://github.com/', '') : undefined,\n track: releaseTag ? 'release' : 'branch',\n commit: upstreamCommit.hash,\n release: releaseTag ?? null,\n url: upstreamGitHubUrl\n ? releaseTag\n ? `${upstreamGitHubUrl}/releases/tag/${releaseTag}`\n : `${upstreamGitHubUrl}/commit/${upstreamCommit.hash}`\n : undefined,\n syncedAt: new Date().toISOString(),\n },\n };\n const recordSyncPoint = async () => {\n await storeLastSyncRef(forkPath, upstreamCommit.hash);\n await writeSyncManifest(forkPath, syncManifest);\n await stagePath(forkPath, MANIFEST_FILE);\n };\n\n if (remainingConflicts.length > 0) {\n // Conflicts: leave MERGE_HEAD intact for IDE 3-way merge resolution. The finishing\n // `cella sync` rerun commits single-parent (`commitSquash`); if the user commits manually\n // instead, the resulting merge commit is flattened away before the branch is pushed\n // (`flattenSyncBranch`) so the PR never lists the whole upstream history.\n await recordSyncPoint();\n onStep?.(\n 'merge in progress',\n formatMergeInProgressDetail(remainingConflicts.length, autoMergedFiles, { forkPath }, 100),\n );\n } else if (totalResolved > 0) {\n const label = synced > 0 ? `${synced} files from upstream` : 'upstream changes';\n // Keep MERGE_HEAD so the finishing rerun can tell a staged sync from a plain dirty\n // tree (`mergeInProgress`) and `git merge --abort` still works. The commit itself is\n // made single-parent at commit time (`commitSquash`).\n await recordSyncPoint();\n onStep?.('synced', `${label} (staged, commit to finish)`);\n } else {\n // Truly nothing changed - clean up merge state\n await mergeAbort(forkPath);\n onStep?.('up to date', 'no upstream changes to sync');\n }\n\n return {\n success: remainingConflicts.length === 0,\n files: analyzedFiles,\n summary,\n conflicts: remainingConflicts,\n autoMergedFiles,\n ...resultMeta(config, ctx),\n };\n}\n\n/**\n * ANALYZE MODE: preview the merge in a temp worktree (invisible to the IDE),\n * classify all files, and discard the worktree — the fork is never touched.\n */\nasync function runAnalyzePreview(\n config: RuntimeConfig,\n ctx: UpstreamContext,\n onProgress?: ProgressCallback,\n onStep?: StepCallback,\n): Promise<MergeResult> {\n const { forkPath } = config;\n const worktreePath = getWorktreePath(forkPath);\n\n // Create worktree in temp directory (invisible to VSCode)\n onProgress?.('creating worktree in temp directory...');\n await createWorktree(forkPath, worktreePath, 'HEAD');\n onStep?.('worktree created', worktreePath);\n\n // Perform merge in worktree (always real merge, never --squash, for correct 3-way).\n // Replace refs are shared across worktrees, so the temporary graft on the fork's HEAD\n // commit steers this worktree merge to the recorded sync point too.\n onProgress?.('performing merge in worktree...');\n await withTemporarySyncBaseGraft(worktreePath, 'HEAD', ctx.mergeBase, () =>\n merge(worktreePath, ctx.upstreamRef, { noCommit: true, noEdit: true }),\n );\n onStep?.('merge complete', 'upstream merged into worktree');\n\n // Analyze all files, then enrich with change dates and commit hashes\n onProgress?.('analyzing files...');\n const analyzedFiles = await analyzeRefs(\n forkPath,\n 'HEAD',\n ctx.upstreamRef,\n ctx.mergeBase,\n syncPredicates(config),\n onProgress,\n );\n await enrichChangeInfo(forkPath, analyzedFiles, ctx.mergeBase, 'HEAD', ctx.upstreamRef);\n onStep?.('analysis complete', `${analyzedFiles.length} files analyzed, dry run — no changes applied`);\n\n onProgress?.('cleaning up worktree...');\n await cleanupWorktree(forkPath, worktreePath);\n\n return {\n success: true,\n files: analyzedFiles,\n summary: calculateSummary(analyzedFiles),\n // For analyze mode, count diverged files as potential conflicts\n conflicts: analyzedFiles.filter((f) => f.status === 'diverged').map((f) => f.path),\n ...resultMeta(config, ctx),\n };\n}\n\n/**\n * Main merge engine entry point: prepare upstream once, then run the requested mode.\n */\nexport async function runMergeEngine(\n config: RuntimeConfig,\n options: {\n apply: boolean;\n onProgress?: ProgressCallback;\n onStep?: StepCallback;\n },\n): Promise<MergeResult> {\n const { forkPath } = config;\n const worktreePath = getWorktreePath(forkPath);\n const { apply, onProgress, onStep } = options;\n\n // Clean up any leftover worktree from a previous interrupted run\n await cleanupLeftoverWorktrees(forkPath);\n\n // Register worktree for cleanup on abort\n registerWorktree(forkPath, worktreePath);\n\n try {\n const ctx = await prepareUpstream(config, onProgress, onStep);\n return apply\n ? await runSyncMerge(config, ctx, onProgress, onStep)\n : await runAnalyzePreview(config, ctx, onProgress, onStep);\n } catch (error) {\n // Clean up on error\n await cleanupWorktree(forkPath, worktreePath);\n throw error;\n }\n}\n","/**\n * Audit service for the Cella CLI.\n *\n * Checks for outdated packages and security vulnerabilities across the monorepo.\n */\n\nimport { spawnSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { checkbox, confirm, Separator } from '@inquirer/prompts';\nimport type { RuntimeConfig } from '../config/types';\nimport {\n type AuditResult,\n buildVulnerabilityMap,\n clearCache,\n type EnhancedPackageInfo,\n fetchNpmMetadata,\n findChangelogUrl,\n formatDependents,\n getHighestSeverity,\n getOutdatedPackages,\n getReleasesUrl,\n getRepoUrl,\n getVulnIcon,\n isMajorVersionChange,\n loadCache,\n middleTruncate,\n runPnpmAudit,\n saveCache,\n type VulnerabilityInfo,\n} from '../utils/audit-utils';\nimport pc from '../utils/colors';\nimport { createSpinner, hyperlink, spinnerSuccess, spinnerText, warningMark } from '../utils/display';\nimport { parseYamlBlockMap } from '../utils/yaml';\n\n/** Options for the audit service */\ninterface AuditOptions {\n /** Whether to bypass pnpm metadata cache for fresh registry data */\n force?: boolean;\n /** Whether to check which pnpm.overrides are still needed */\n checkOverrides?: boolean;\n}\n\n/**\n * Audit service - checks for outdated packages and security vulnerabilities.\n */\nexport async function runAudit(config: RuntimeConfig, options: AuditOptions = {}): Promise<void> {\n const { forkPath } = config;\n\n // Handle check-overrides mode\n if (options.checkOverrides) {\n await checkOverrides(forkPath);\n return;\n }\n\n const spinner = createSpinner('checking for outdated packages & vulnerabilities...');\n try {\n // Clear pnpm metadata cache when force is set to get fresh registry data\n if (options.force) {\n spinnerText('clearing pnpm metadata cache...');\n clearCache();\n spawnSync('pnpm', ['cache', 'delete', '*'], {\n cwd: forkPath,\n stdio: 'ignore',\n });\n spinnerText('checking for outdated packages & vulnerabilities...');\n }\n\n // Run outdated check and audit in parallel\n const [outdatedPackages, auditResult] = await Promise.all([getOutdatedPackages(forkPath), runPnpmAudit(forkPath)]);\n\n const packageNames = Object.keys(outdatedPackages);\n const vulnMap = buildVulnerabilityMap(auditResult);\n\n if (packageNames.length === 0 && vulnMap.size === 0) {\n spinnerSuccess('all packages are up to date and secure');\n return;\n }\n\n // Load cache for changelog URLs\n const cache = loadCache();\n\n spinnerText(`found ${packageNames.length} outdated package(s) - fetching metadata...`);\n\n // Read each dependent's package.json once; used for display names and pin detection.\n type DependentPkgJson = { name?: string } & Partial<\n Record<'dependencies' | 'devDependencies', Record<string, string>>\n >;\n const pkgJsonCache = new Map<string, DependentPkgJson | null>();\n const readDependentPkg = (location: string): DependentPkgJson | null => {\n let cached = pkgJsonCache.get(location);\n if (cached === undefined) {\n try {\n cached = JSON.parse(fs.readFileSync(path.join(location, 'package.json'), 'utf-8'));\n } catch {\n cached = null;\n }\n pkgJsonCache.set(location, cached ?? null);\n }\n return cached ?? null;\n };\n\n const dependentNameCache = new Map<string, string>();\n for (const name of packageNames) {\n for (const dep of outdatedPackages[name].dependentPackages) {\n if (!dependentNameCache.has(dep.location)) {\n dependentNameCache.set(dep.location, readDependentPkg(dep.location)?.name || path.basename(dep.location));\n }\n }\n }\n\n // Fetch metadata for all packages in parallel (with concurrency limit)\n const enhancedPackages: EnhancedPackageInfo[] = [];\n const batchSize = 10;\n\n for (let i = 0; i < packageNames.length; i += batchSize) {\n const batch = packageNames.slice(i, i + batchSize);\n const results = await Promise.all(\n batch.map(async (name) => {\n const pkg = outdatedPackages[name];\n const metadata = await fetchNpmMetadata(name);\n const repoUrl = getRepoUrl(metadata);\n const changelogUrl = await findChangelogUrl(repoUrl, name, cache);\n\n // Detect workspaces where this package is pinned (exact version, no ^ or ~)\n const pinnedIn: string[] = [];\n for (const d of pkg.dependentPackages) {\n const spec = readDependentPkg(d.location)?.[pkg.dependencyType]?.[name] || '';\n if (spec && !spec.startsWith('^') && !spec.startsWith('~') && !spec.startsWith('>')) {\n pinnedIn.push(d.name);\n }\n }\n\n return {\n name,\n current: pkg.current,\n latest: pkg.latest,\n dependents: pkg.dependentPackages.map((d) => d.name),\n dependentLocations: pkg.dependentPackages.map((d) => d.location),\n isDev: pkg.dependencyType === 'devDependencies',\n isMajorUpdate: isMajorVersionChange(pkg.current, pkg.latest),\n pinnedIn,\n repoUrl,\n changelogUrl,\n releasesUrl: getReleasesUrl(repoUrl),\n vulnerabilities: vulnMap.get(name) || [],\n };\n }),\n );\n enhancedPackages.push(...results);\n }\n\n // Save updated cache\n saveCache(cache);\n\n // Sort: by dependents (primary), then alphabetically (secondary)\n enhancedPackages.sort((a, b) => {\n const depA = formatDependents(a.dependents);\n const depB = formatDependents(b.dependents);\n const depCompare = depA.localeCompare(depB);\n if (depCompare !== 0) return depCompare;\n return a.name.localeCompare(b.name);\n });\n\n spinner.stop();\n\n // Print results\n if (enhancedPackages.length > 0) {\n printOutdatedResults(enhancedPackages, dependentNameCache, forkPath);\n }\n printVulnerabilityResults(auditResult, vulnMap);\n\n // Interactive update prompt (skip in non-interactive/list mode)\n // Show when there are outdated packages OR vulnerabilities to fix\n const hasVulns = vulnMap.size > 0;\n if ((enhancedPackages.length > 0 || hasVulns) && !config.list) {\n await promptForUpdates(enhancedPackages, forkPath, auditResult);\n }\n } finally {\n spinner.stop();\n }\n}\n\n/**\n * Print outdated packages results table.\n */\nfunction printOutdatedResults(\n enhancedPackages: EnhancedPackageInfo[],\n dependentNameCache: Map<string, string>,\n forkPath: string,\n): void {\n // Calculate column widths\n const DEV_TAG = ' (dev)';\n const MAX_NAME_LEN = 35;\n const MAX_DEPENDENTS_LEN = 15;\n const maxNameLen = Math.min(\n MAX_NAME_LEN,\n Math.max(7, ...enhancedPackages.map((p) => p.name.length + (p.isDev ? DEV_TAG.length : 0))),\n );\n const maxCurrentLen = Math.max(7, ...enhancedPackages.map((p) => p.current.length));\n const maxLatestLen = Math.max(6, ...enhancedPackages.map((p) => p.latest.length));\n const maxDependentsLen = Math.min(\n MAX_DEPENDENTS_LEN,\n Math.max(10, ...enhancedPackages.map((p) => formatDependents(p.dependents).length)),\n );\n\n // Header (vuln column is just a dot, so minimal width)\n const header = [\n ' ',\n pc.bold('package'.padEnd(maxNameLen)),\n pc.bold('current'.padEnd(maxCurrentLen)),\n pc.bold('latest'.padEnd(maxLatestLen)),\n pc.bold('in'.padEnd(maxDependentsLen)),\n pc.bold('links'),\n ].join(' ');\n\n console.info(header);\n\n // Rows\n for (const pkg of enhancedPackages) {\n // Vulnerability indicator\n const highestSeverity = getHighestSeverity(pkg.vulnerabilities);\n const vulnIndicator = highestSeverity ? getVulnIcon(highestSeverity) : ' ';\n\n // Package name (with dev tag, truncated if needed)\n const fullName = pkg.isDev ? `${pkg.name}${DEV_TAG}` : pkg.name;\n const displayName = middleTruncate(fullName, maxNameLen);\n const name = pc.white(displayName.padEnd(maxNameLen));\n\n // Version columns\n const current = pc.red(pkg.current.padEnd(maxCurrentLen));\n const latestText = pkg.latest.padEnd(maxLatestLen);\n const latest = pkg.isMajorUpdate ? pc.bold(pc.green(latestText)) : pc.green(latestText);\n\n // Dependents (compact format)\n const dependentsText = formatDependents(pkg.dependents);\n const dependents = pc.dim(middleTruncate(dependentsText, maxDependentsLen).padEnd(maxDependentsLen));\n\n // Build links (compact)\n const links: string[] = [];\n if (pkg.changelogUrl) {\n links.push(hyperlink(pc.magenta('log'), pkg.changelogUrl));\n }\n if (pkg.releasesUrl) {\n links.push(hyperlink(pc.blue('rel'), pkg.releasesUrl));\n }\n if (pkg.repoUrl) {\n links.push(hyperlink(pc.cyan('repo'), pkg.repoUrl));\n }\n\n const linksStr = links.length > 0 ? links.join(' ') : pc.dim('n/a');\n\n console.info(`${vulnIndicator} ${name} ${current} ${latest} ${dependents} ${linksStr}`);\n }\n\n // Package.json links with counts by dependent name\n console.info();\n // Build map of dependent name -> { location, count } using pre-cached names\n const dependentMap = new Map<string, { location: string; count: number }>();\n for (const pkg of enhancedPackages) {\n for (const loc of pkg.dependentLocations) {\n const dependentName = dependentNameCache.get(loc) || path.basename(loc);\n const existing = dependentMap.get(dependentName);\n if (existing) {\n existing.count++;\n } else {\n dependentMap.set(dependentName, { location: loc, count: 1 });\n }\n }\n }\n const sortedDependents = [...dependentMap.entries()].sort((a, b) => a[0].localeCompare(b[0]));\n // Calculate max dependent name length for alignment\n const maxDependentNameLen = Math.max(0, ...sortedDependents.map(([name]) => name.length));\n for (const [dependentName, { location, count }] of sortedDependents) {\n const packageJsonPath = path.join(location, 'package.json');\n const relativePath = path.relative(forkPath, packageJsonPath);\n const paddedName = dependentName.padEnd(maxDependentNameLen);\n console.info(\n ` ${pc.dim('•')} ${paddedName} ${hyperlink(relativePath, `file://${packageJsonPath}`)} ${pc.dim(`${count}`)}`,\n );\n }\n}\n\n/**\n * Prompt user to select packages to update, then run pnpm up.\n */\nasync function promptForUpdates(\n packages: EnhancedPackageInfo[],\n forkPath: string,\n auditResult: AuditResult | null,\n): Promise<void> {\n const hasVulnerabilities =\n auditResult !== null && Object.values(auditResult.metadata?.vulnerabilities || {}).some((c) => c > 0);\n const hasPackages = packages.length > 0;\n\n // Ask if user wants to proceed (message adapts to what's available)\n let confirmMessage = 'update packages?';\n if (hasVulnerabilities && hasPackages) {\n confirmMessage = 'update packages and fix vulnerabilities?';\n } else if (hasVulnerabilities) {\n confirmMessage = 'fix vulnerabilities?';\n }\n\n let wantsUpdate: boolean;\n try {\n wantsUpdate = await confirm({\n message: confirmMessage,\n default: true,\n });\n } catch {\n return;\n }\n if (!wantsUpdate) return;\n\n console.info();\n\n // Build choice item for a package\n const makeChoice = (pkg: EnhancedPackageInfo) => {\n const devTag = pkg.isDev ? pc.dim(' (dev)') : '';\n const version = `${pc.red(pkg.current)} → ${pc.green(pkg.latest)}`;\n const pinnedWarning =\n pkg.pinnedIn.length > 0 ? ` ${warningMark} ${pc.dim(`pinned in ${pkg.pinnedIn.join(', ')}`)}` : '';\n return {\n name: `${pkg.name}${devTag} ${version}${pinnedWarning}`,\n value: pkg.name,\n checked: false,\n };\n };\n\n // Sentinel value for the audit --fix checkbox\n const AUDIT_FIX_VALUE = '__audit_fix__';\n\n // Split packages into groups: pinned and regular\n const pinned = packages.filter((p) => p.pinnedIn.length > 0);\n const regular = packages.filter((p) => p.pinnedIn.length === 0);\n\n // Build grouped choices with separators\n const choices: Array<{ name: string; value: string; checked: boolean } | Separator> = [];\n\n // Add audit --fix checkbox at the top when vulnerabilities exist\n if (hasVulnerabilities) {\n const vulnMeta = auditResult?.metadata?.vulnerabilities || {};\n const parts: string[] = [];\n if (vulnMeta.critical) parts.push(pc.red(`${vulnMeta.critical} critical`));\n if (vulnMeta.high) parts.push(pc.red(`${vulnMeta.high} high`));\n if (vulnMeta.moderate) parts.push(pc.yellow(`${vulnMeta.moderate} moderate`));\n if (vulnMeta.low) parts.push(pc.blue(`${vulnMeta.low} low`));\n const vulnSummary = parts.length > 0 ? ` ${pc.dim('·')} ${parts.join(' ')}` : '';\n choices.push(new Separator(pc.red(`── vulnerabilities${vulnSummary} ──`)));\n choices.push({\n name: `${pc.cyan('pnpm audit --fix override')} ${pc.dim('add overrides for non-vulnerable versions')}`,\n value: AUDIT_FIX_VALUE,\n checked: false,\n });\n }\n\n if (pinned.length > 0) {\n choices.push(new Separator(pc.yellow(`── pinned (${pinned.length}) ──`)));\n choices.push(...pinned.map(makeChoice));\n }\n if (regular.length > 0) {\n if (pinned.length > 0 || hasVulnerabilities) {\n choices.push(new Separator(pc.dim(`── packages (${regular.length}) ──`)));\n }\n choices.push(...regular.map(makeChoice));\n }\n\n let selected: string[];\n try {\n selected = await checkbox({\n message: 'toggle packages to update',\n choices,\n required: true,\n pageSize: 20,\n loop: false,\n theme: {\n icon: {\n cursor: '❯ ',\n },\n style: {\n highlight: (text: string) => text,\n keysHelpTip: (keys: [string, string][]) => {\n const tips = keys.map(([key, action]: [string, string]) => `${pc.dim(key)} ${action}`);\n return tips.join(' ');\n },\n renderSelectedChoices: (selectedChoices: Array<{ value?: string }>) =>\n pc.dim(`${selectedChoices.length} package${selectedChoices.length !== 1 ? 's' : ''} selected`),\n },\n },\n });\n } catch {\n // User pressed Ctrl+C or escaped\n return;\n }\n\n // Extract audit --fix selection and filter it from package selections\n const runAuditFix = selected.includes(AUDIT_FIX_VALUE);\n const selectedPackages = selected.filter((s) => s !== AUDIT_FIX_VALUE);\n\n // Print summary of what will happen\n const summaryParts: string[] = [];\n if (selectedPackages.length > 0) {\n summaryParts.push(`updating ${selectedPackages.length} package${selectedPackages.length !== 1 ? 's' : ''}`);\n }\n if (runAuditFix) {\n summaryParts.push('then updating dependencies');\n }\n console.info();\n console.info(pc.green(`✓ ${summaryParts.join(' ')}`));\n console.info();\n\n // Check if any major updates are selected\n const selectedMajor = packages.filter((p) => selectedPackages.includes(p.name) && p.isMajorUpdate);\n if (selectedMajor.length > 0) {\n const majorNames = selectedMajor.map((p) => pc.bold(p.name)).join(', ');\n try {\n const proceed = await confirm({\n message: `${selectedMajor.length} major update${selectedMajor.length > 1 ? 's' : ''} selected (${majorNames}). proceed?`,\n default: true,\n });\n if (!proceed) {\n console.info(pc.dim(' update cancelled'));\n return;\n }\n } catch {\n return;\n }\n }\n\n const catalogPackages = readCatalogPackageNames(forkPath);\n\n // Group selected packages by workspace\n const workspacePackages = new Map<string, { packages: string[] }>();\n for (const pkgName of selectedPackages) {\n const pkg = packages.find((p) => p.name === pkgName);\n if (!pkg) continue;\n\n for (let i = 0; i < pkg.dependents.length; i++) {\n const dependent = pkg.dependents[i];\n if (!workspacePackages.has(dependent)) {\n workspacePackages.set(dependent, { packages: [] });\n }\n workspacePackages.get(dependent)?.packages.push(pkgName);\n }\n }\n\n // Run pnpm audit --fix first (before package updates) so overrides are applied during install\n if (runAuditFix) {\n console.info(pc.dim('running pnpm audit --fix override...'));\n const auditFixResult = spawnSync('pnpm', ['audit', '--fix', 'override'], {\n cwd: forkPath,\n stdio: 'inherit',\n });\n\n console.info();\n if (auditFixResult.status === 0) {\n console.info(pc.green('✓ pnpm audit --fix override completed'));\n } else {\n console.error(pc.red(`✗ pnpm audit --fix override failed (exit code ${auditFixResult.status})`));\n }\n }\n\n // Summarize impacted workspaces before running a single workspace-wide update.\n // The two-phase normalization below guards against catalog version mismatches\n // (ERR_PNPM_CATALOG_VERSION_MISMATCH) that could occur under catalogMode=strict.\n // The workspace now uses catalogMode=manual, so this is defensive only, but it\n // remains harmless and keeps audit robust if strict mode is ever reintroduced.\n for (const [workspace, { packages: pkgs }] of workspacePackages) {\n const pkgList = pkgs.join(', ');\n console.info(`${pc.cyan('↑')} ${pc.bold(workspace)}: ${pc.dim(pkgList)}`);\n }\n\n if (selectedPackages.length > 0) {\n console.info();\n\n const selectedCatalogPackages = selectedPackages.filter((pkgName) => catalogPackages.has(pkgName));\n\n if (selectedCatalogPackages.length > 0) {\n console.info(pc.dim(`normalizing catalog consumers: ${selectedCatalogPackages.join(', ')}`));\n const normalizeResult = spawnSync('pnpm', ['-r', 'up', ...selectedCatalogPackages], {\n cwd: forkPath,\n stdio: 'inherit',\n });\n\n console.info();\n if (normalizeResult.status !== 0) {\n console.error(pc.red(`✗ catalog normalization failed (exit code ${normalizeResult.status})`));\n return;\n }\n }\n\n // Run one recursive update so pnpm can rewrite catalogs and direct consumers atomically.\n const result = spawnSync('pnpm', ['-r', 'up', '--latest', ...selectedPackages], {\n cwd: forkPath,\n stdio: 'inherit',\n });\n\n console.info();\n if (result.status === 0) {\n console.info(pc.green(`✓ ${selectedPackages.length} package${selectedPackages.length > 1 ? 's' : ''} updated`));\n } else {\n console.error(pc.red(`✗ update failed (exit code ${result.status})`));\n }\n }\n}\n\n/**\n * Print vulnerability summary section.\n */\nfunction printVulnerabilityResults(auditResult: AuditResult | null, vulnMap: Map<string, VulnerabilityInfo[]>): void {\n if (auditResult && vulnMap.size > 0) {\n const vulnMeta = auditResult.metadata?.vulnerabilities || {};\n const criticalCount = vulnMeta.critical || 0;\n const highCount = vulnMeta.high || 0;\n const moderateCount = vulnMeta.moderate || 0;\n const lowCount = vulnMeta.low || 0;\n\n console.info();\n console.info(\n `${pc.red('⚠')} ${pc.bold('vulnerabilities')} ${pc.dim('·')} ` +\n (criticalCount > 0 ? pc.red(`${criticalCount} critical `) : '') +\n (highCount > 0 ? pc.red(`${highCount} high `) : '') +\n (moderateCount > 0 ? pc.yellow(`${moderateCount} moderate `) : '') +\n (lowCount > 0 ? pc.blue(`${lowCount} low`) : ''),\n );\n console.info('─'.repeat(60));\n\n // List vulnerable packages with details\n for (const [pkgName, vulns] of vulnMap.entries()) {\n for (const vuln of vulns) {\n const severityIcon = getVulnIcon(vuln.severity);\n const cveStr = vuln.cves.length > 0 ? pc.dim(` ${vuln.cves[0]}`) : '';\n // Build source info: \"in workspace via direct-dep\" or just \"in workspace\"\n let sourceStr = '';\n if (vuln.workspace) {\n sourceStr = pc.dim(` in ${vuln.workspace}`);\n if (vuln.directDependency) {\n sourceStr += pc.dim(` via ${vuln.directDependency}`);\n }\n }\n const title = middleTruncate(vuln.title, 60);\n console.info(\n `${severityIcon} ${pc.white(pkgName)} ${pc.dim(vuln.vulnerableVersions)}${sourceStr} ${pc.dim('·')} ${title}${cveStr}`,\n );\n }\n }\n } else {\n console.info();\n console.info(`${pc.green('✓')} no vulnerabilities found`);\n }\n\n console.info();\n}\n\nfunction readCatalogPackageNames(forkPath: string): Set<string> {\n const workspacePath = path.join(forkPath, 'pnpm-workspace.yaml');\n try {\n const content = fs.readFileSync(workspacePath, 'utf-8');\n return new Set(Object.keys(parseYamlBlockMap(content, 'catalog')));\n } catch {\n return new Set();\n }\n}\n\n/**\n * Reads all pnpm.overrides from package.json and pnpm-workspace.yaml.\n * Returns a map of override key -> { target version, source file }.\n */\nfunction readOverrides(forkPath: string): Map<string, { target: string; source: string }> {\n const overrides = new Map<string, { target: string; source: string }>();\n\n // Read from package.json pnpm.overrides\n const pkgJsonPath = path.join(forkPath, 'package.json');\n try {\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n const pnpmOverrides = pkgJson.pnpm?.overrides || {};\n for (const [key, value] of Object.entries(pnpmOverrides)) {\n overrides.set(key, { target: value as string, source: 'package.json' });\n }\n } catch {\n // skip\n }\n\n // Read from pnpm-workspace.yaml overrides\n const workspacePath = path.join(forkPath, 'pnpm-workspace.yaml');\n try {\n const content = fs.readFileSync(workspacePath, 'utf-8');\n const wsOverrides = parseYamlBlockMap(content, 'overrides');\n for (const [key, value] of Object.entries(wsOverrides)) {\n overrides.set(key, { target: value, source: 'pnpm-workspace.yaml' });\n }\n } catch {\n // skip\n }\n\n return overrides;\n}\n\n/**\n * Checks which pnpm.overrides are still needed by cross-referencing\n * with current audit results and installed versions.\n */\nasync function checkOverrides(forkPath: string): Promise<void> {\n const spinner = createSpinner('checking overrides against current audit...');\n\n const overrides = readOverrides(forkPath);\n\n if (overrides.size === 0) {\n spinnerSuccess('no pnpm.overrides found');\n return;\n }\n\n // Run audit to see current vulnerabilities\n const auditResult = await runPnpmAudit(forkPath);\n\n // Build set of currently vulnerable package names from advisories\n const activeAdvisoryPackages = new Set<string>();\n if (auditResult?.advisories) {\n for (const advisory of Object.values(auditResult.advisories)) {\n activeAdvisoryPackages.add(advisory.module_name);\n }\n }\n\n spinner.stop();\n\n // Categorize each override\n const securityOverrides: Array<{ key: string; pkg: string; target: string; source: string; status: string }> = [];\n const pinOverrides: Array<{ key: string; target: string; source: string }> = [];\n\n for (const [key, { target, source }] of overrides) {\n // Security overrides have version selectors like \"pkg@<=1.0.0\" or \"pkg@>=1.0.0 <2.0.0\"\n const atIndex = key.indexOf('@', key.startsWith('@') ? 1 : 0);\n if (atIndex > 0) {\n const pkg = key.slice(0, atIndex);\n const hasActiveAdvisory = activeAdvisoryPackages.has(pkg);\n const status = hasActiveAdvisory ? 'active' : 'likely stale';\n securityOverrides.push({ key, pkg, target, source, status });\n } else {\n pinOverrides.push({ key, target, source });\n }\n }\n\n // Print results\n const allKeys = Array.from(overrides.keys());\n const allValues = Array.from(overrides.values());\n const maxKeyLen = Math.max(8, ...allKeys.map((k) => k.length));\n const maxTargetLen = Math.max(6, ...allValues.map((v) => v.target.length));\n\n if (securityOverrides.length > 0) {\n console.info(pc.bold(`security overrides (${securityOverrides.length})`));\n console.info('─'.repeat(60));\n\n for (const o of securityOverrides) {\n const icon = o.status === 'active' ? pc.red('●') : pc.green('○');\n const statusText = o.status === 'active' ? pc.red('active') : pc.green('likely stale');\n const keyText = pc.white(o.key.padEnd(maxKeyLen));\n const targetText = pc.dim(o.target.padEnd(maxTargetLen));\n const sourceText = pc.dim(o.source);\n console.info(` ${icon} ${keyText} → ${targetText} ${statusText} ${sourceText}`);\n }\n console.info();\n }\n\n if (pinOverrides.length > 0) {\n console.info(pc.bold(`version pins (${pinOverrides.length})`));\n console.info('─'.repeat(60));\n\n for (const o of pinOverrides) {\n const keyText = pc.white(o.key.padEnd(maxKeyLen));\n const targetText = pc.dim(o.target.padEnd(maxTargetLen));\n const sourceText = pc.dim(o.source);\n console.info(` ${pc.blue('◆')} ${keyText} → ${targetText} ${sourceText}`);\n }\n console.info();\n }\n\n // Summary\n const staleCount = securityOverrides.filter((o) => o.status === 'likely stale').length;\n const activeCount = securityOverrides.filter((o) => o.status === 'active').length;\n\n if (staleCount > 0) {\n console.info(\n `${pc.green('○')} ${staleCount} override${staleCount !== 1 ? 's' : ''} likely stale — no matching advisory found in current audit`,\n );\n console.info(pc.dim(' overrides mask vulnerabilities — verify by temporarily removing and running pnpm audit'));\n }\n if (activeCount > 0) {\n console.info(\n `${pc.red('●')} ${activeCount} override${activeCount !== 1 ? 's' : ''} still active — advisory present without override`,\n );\n }\n if (pinOverrides.length > 0) {\n console.info(\n `${pc.blue('◆')} ${pinOverrides.length} version pin${pinOverrides.length !== 1 ? 's' : ''} — not security-related, review manually`,\n );\n }\n console.info();\n}\n","/**\n * Audit utilities for the Cella CLI audit service.\n *\n * Provides npm registry fetching, changelog detection, vulnerability parsing, and caching.\n */\n\nimport { execFile } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { promisify } from 'node:util';\nimport pc from './colors';\n\nconst execFileAsync = promisify(execFile);\n\n/*************************************************************************************************\n * Types\n ************************************************************************************************/\n\ninterface OutdatedPackage {\n current: string;\n latest: string;\n wanted: string;\n isDeprecated: boolean;\n dependencyType: 'dependencies' | 'devDependencies';\n dependentPackages: Array<{ name: string; location: string }>;\n}\n\nexport interface NpmRegistryData {\n repository?: { type: string; url: string; directory?: string };\n homepage?: string;\n bugs?: { url: string };\n}\n\ninterface CachedPackageData {\n repoUrl: string | null;\n changelogUrl: string | null;\n fetchedAt: number;\n}\n\ninterface ChangelogCache {\n [packageName: string]: CachedPackageData;\n}\n\nexport interface EnhancedPackageInfo {\n name: string;\n current: string;\n latest: string;\n dependents: string[];\n dependentLocations: string[];\n isDev: boolean;\n isMajorUpdate: boolean;\n /** Workspace names where this package is pinned to an exact version (no ^ or ~) */\n pinnedIn: string[];\n repoUrl: string | null;\n changelogUrl: string | null;\n releasesUrl: string | null;\n vulnerabilities: VulnerabilityInfo[];\n}\n\n/** Vulnerability severity levels */\nexport type VulnerabilitySeverity = 'critical' | 'high' | 'moderate' | 'low' | 'info';\n\n/** Vulnerability info for a package */\nexport interface VulnerabilityInfo {\n id: number;\n title: string;\n severity: VulnerabilitySeverity;\n url: string;\n vulnerableVersions: string;\n patchedVersions: string;\n cves: string[];\n /** The workspace/dependent containing this vulnerability (e.g., 'frontend', 'backend') */\n workspace: string | null;\n /** The direct dependency in the workspace that brought in this vulnerable package */\n directDependency: string | null;\n}\n\n/** Audit result from pnpm audit --json */\nexport interface AuditResult {\n advisories: Record<string, AuditAdvisory>;\n metadata: {\n vulnerabilities: Record<VulnerabilitySeverity, number>;\n dependencies: number;\n devDependencies: number;\n };\n}\n\nexport interface AuditAdvisory {\n id: number;\n title: string;\n module_name: string;\n severity: VulnerabilitySeverity;\n vulnerable_versions: string;\n patched_versions: string;\n cves: string[];\n url: string;\n findings: Array<{ version: string; paths: string[] }>;\n}\n\n/** Parsed dependency path info from pnpm audit */\ninterface DependencyPathInfo {\n /** The workspace name (e.g., 'frontend', 'backend') */\n workspace: string | null;\n /** The direct dependency in the workspace that starts the chain */\n directDependency: string | null;\n}\n\n/*************************************************************************************************\n * Constants\n ************************************************************************************************/\n\n/** Cache file location (in cli/cella directory) */\nexport const CACHE_FILE = path.join(import.meta.dirname, '..', '..', '.audit.cache.json');\n\n/** Cache TTL: 7 days in ms */\nconst CACHE_TTL = 7 * 24 * 60 * 60 * 1000;\n\n/** Common changelog file paths to check in GitHub repos */\nexport const CHANGELOG_PATHS = ['CHANGELOG.md', 'CHANGELOG', 'changelog.md', 'HISTORY.md', 'CHANGES.md', 'NEWS.md'];\n\n/** Default branches to check for changelog files */\nexport const DEFAULT_BRANCHES = ['main', 'master'] as const;\n\n/*************************************************************************************************\n * Cache Functions\n ************************************************************************************************/\n\n/** Loads the changelog cache from disk. */\nexport function loadCache(): ChangelogCache {\n try {\n if (fs.existsSync(CACHE_FILE)) {\n return JSON.parse(fs.readFileSync(CACHE_FILE, 'utf-8'));\n }\n } catch {\n // Ignore cache read errors\n }\n return {};\n}\n\n/** Saves the changelog cache to disk. */\nexport function saveCache(cache: ChangelogCache): void {\n try {\n fs.writeFileSync(CACHE_FILE, `${JSON.stringify(cache, null, 2)}\\n`);\n } catch {\n // Ignore cache write errors\n }\n}\n\n/** Clears the changelog cache. */\nexport function clearCache(): void {\n try {\n if (fs.existsSync(CACHE_FILE)) {\n fs.unlinkSync(CACHE_FILE);\n console.info(pc.green('✓ cache cleared successfully'));\n } else {\n console.info(pc.yellow('no cache file found'));\n }\n } catch (err) {\n console.error(pc.red('failed to clear cache:'), err);\n }\n}\n\n/*************************************************************************************************\n * NPM Registry Functions\n ************************************************************************************************/\n\n/** Fetches package metadata from npm registry. */\nexport async function fetchNpmMetadata(packageName: string): Promise<NpmRegistryData | null> {\n try {\n const response = await fetch(`https://registry.npmjs.org/${packageName}`);\n if (!response.ok) return null;\n return (await response.json()) as NpmRegistryData;\n } catch {\n return null;\n }\n}\n\n/**\n * Extracts GitHub repo URL from npm registry data.\n * Normalizes git+https:// URLs to https:// format.\n */\nexport function getRepoUrl(data: NpmRegistryData | null): string | null {\n if (!data?.repository?.url) return null;\n\n let url = data.repository.url;\n\n // Normalize git+https:// to https://\n if (url.startsWith('git+')) {\n url = url.slice(4);\n }\n\n // Remove .git suffix\n if (url.endsWith('.git')) {\n url = url.slice(0, -4);\n }\n\n // Convert git:// to https://\n if (url.startsWith('git://')) {\n url = url.replace('git://', 'https://');\n }\n\n return url;\n}\n\n/** Checks whether the provided URL points to a GitHub repository. */\nfunction isGitHubRepoUrl(repoUrl: string | null): repoUrl is string {\n if (!repoUrl) return false;\n try {\n const parsed = new URL(repoUrl);\n return parsed.hostname === 'github.com' || parsed.hostname === 'www.github.com';\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if a file exists in a GitHub repo and returns the branch name if found.\n * Returns null if file doesn't exist on any branch.\n */\nasync function findGitHubFile(repoUrl: string, filePath: string): Promise<string | null> {\n if (!isGitHubRepoUrl(repoUrl)) return null;\n\n for (const branch of DEFAULT_BRANCHES) {\n const rawUrl = repoUrl.replace('github.com', 'raw.githubusercontent.com').concat(`/${branch}/${filePath}`);\n\n try {\n const response = await fetch(rawUrl, { method: 'HEAD' });\n if (response.ok) return branch;\n } catch {\n // Continue to next branch\n }\n }\n return null;\n}\n\n/**\n * Finds the changelog URL for a package by checking common locations.\n * Results are cached to avoid repeated GitHub requests.\n */\nexport async function findChangelogUrl(\n repoUrl: string | null,\n packageName: string,\n cache: ChangelogCache,\n): Promise<string | null> {\n if (!isGitHubRepoUrl(repoUrl)) return null;\n\n // Check cache first\n const cached = cache[packageName];\n if (cached && Date.now() - cached.fetchedAt < CACHE_TTL) {\n return cached.changelogUrl;\n }\n\n // Try each common changelog path - findGitHubFile returns branch if found\n for (const changelogPath of CHANGELOG_PATHS) {\n const branch = await findGitHubFile(repoUrl, changelogPath);\n if (branch) {\n const blobUrl = `${repoUrl}/blob/${branch}/${changelogPath}`;\n // Cache the result\n cache[packageName] = {\n repoUrl,\n changelogUrl: blobUrl,\n fetchedAt: Date.now(),\n };\n return blobUrl;\n }\n }\n\n // No changelog found, cache negative result\n cache[packageName] = {\n repoUrl,\n changelogUrl: null,\n fetchedAt: Date.now(),\n };\n\n return null;\n}\n\n/** Get GitHub releases URL */\nexport function getReleasesUrl(repoUrl: string | null): string | null {\n if (!isGitHubRepoUrl(repoUrl)) return null;\n return `${repoUrl}/releases`;\n}\n\n/*************************************************************************************************\n * Version Utilities\n ************************************************************************************************/\n\n/** Checks if the update is a major version change. */\nexport function isMajorVersionChange(current: string, latest: string): boolean {\n const currentMajor = current.split('.')[0]?.replace(/^\\D+/, '');\n const latestMajor = latest.split('.')[0]?.replace(/^\\D+/, '');\n if (!currentMajor || !latestMajor) return false;\n return Number.parseInt(latestMajor, 10) > Number.parseInt(currentMajor, 10);\n}\n\n/*************************************************************************************************\n * Outdated Package Functions\n ************************************************************************************************/\n\n/**\n * Runs pnpm outdated and returns JSON output.\n * Note: pnpm outdated exits with code 1 when packages are outdated,\n * so we need to handle this as a normal case, not an error.\n */\nexport async function getOutdatedPackages(cwd: string): Promise<Record<string, OutdatedPackage>> {\n try {\n const { stdout } = await execFileAsync('pnpm', ['-r', 'outdated', '--json'], {\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024, // 10MB buffer for large outputs\n cwd,\n });\n\n if (!stdout || stdout.trim() === '') {\n return {};\n }\n\n return JSON.parse(stdout);\n } catch (error) {\n // pnpm outdated exits with code 1 when there are outdated packages\n // This is expected behavior, not an error\n if (error instanceof Error && 'stdout' in error) {\n const stdout = (error as { stdout: string }).stdout;\n if (stdout?.trim()) {\n try {\n return JSON.parse(stdout);\n } catch {\n // JSON parse failed, return empty\n return {};\n }\n }\n }\n return {};\n }\n}\n\n/*************************************************************************************************\n * Vulnerability Functions\n ************************************************************************************************/\n\n/**\n * Runs pnpm audit and returns parsed JSON output.\n * Returns null if audit fails or no vulnerabilities found.\n */\nexport async function runPnpmAudit(cwd: string): Promise<AuditResult | null> {\n try {\n const { stdout } = await execFileAsync('pnpm', ['audit', '--json'], {\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024,\n cwd,\n });\n\n if (!stdout || stdout.trim() === '') {\n return null;\n }\n\n return JSON.parse(stdout) as AuditResult;\n } catch (error) {\n // pnpm audit exits with non-zero when vulnerabilities found\n if (error instanceof Error && 'stdout' in error) {\n const stdout = (error as { stdout: string }).stdout;\n if (stdout?.trim()) {\n try {\n return JSON.parse(stdout) as AuditResult;\n } catch {\n return null;\n }\n }\n }\n return null;\n }\n}\n\n/**\n * Parses vulnerability paths to extract workspace and direct dependency.\n * Path format is like \"workspace>direct-dep>transitive>vulnerable-pkg\".\n * Examples:\n * - \"frontend>virtua>solid-js>seroval\" -> { workspace: 'frontend', directDependency: 'virtua' }\n * - \"backend>jsx-email>esbuild\" -> { workspace: 'backend', directDependency: 'jsx-email' }\n * - \"esbuild\" (direct) -> { workspace: null, directDependency: null }\n */\nfunction parseDependencyPath(paths: string[]): DependencyPathInfo {\n for (const pathStr of paths) {\n const parts = pathStr.split('>');\n if (parts.length >= 2) {\n // First part is workspace, second is the direct dependency in that workspace\n return {\n workspace: parts[0],\n directDependency: parts.length > 2 ? parts[1] : null,\n };\n }\n }\n return { workspace: null, directDependency: null };\n}\n\n/** Creates a map of package name -> vulnerabilities from audit result. */\nexport function buildVulnerabilityMap(auditResult: AuditResult | null): Map<string, VulnerabilityInfo[]> {\n const map = new Map<string, VulnerabilityInfo[]>();\n if (!auditResult?.advisories) return map;\n\n for (const advisory of Object.values(auditResult.advisories)) {\n // Extract workspace and direct dependency from findings paths\n const allPaths = advisory.findings?.flatMap((f) => f.paths) || [];\n const { workspace, directDependency } = parseDependencyPath(allPaths);\n\n const existing = map.get(advisory.module_name) || [];\n existing.push({\n id: advisory.id,\n title: advisory.title,\n severity: advisory.severity,\n url: advisory.url,\n vulnerableVersions: advisory.vulnerable_versions,\n patchedVersions: advisory.patched_versions,\n cves: advisory.cves || [],\n workspace,\n directDependency,\n });\n map.set(advisory.module_name, existing);\n }\n\n return map;\n}\n\n/*************************************************************************************************\n * Display Utilities\n ************************************************************************************************/\n\n/** Gets vulnerability severity icon with color. */\nexport function getVulnIcon(severity: VulnerabilitySeverity): string {\n switch (severity) {\n case 'critical':\n return pc.red('●');\n case 'high':\n return pc.red('●');\n case 'moderate':\n return pc.yellow('●');\n case 'low':\n return pc.blue('●');\n default:\n return pc.gray('●');\n }\n}\n\n/** Gets the highest severity from a list of vulnerabilities. */\nexport function getHighestSeverity(vulns: VulnerabilityInfo[]): VulnerabilitySeverity | null {\n if (vulns.length === 0) return null;\n const order: VulnerabilitySeverity[] = ['critical', 'high', 'moderate', 'low', 'info'];\n for (const severity of order) {\n if (vulns.some((v) => v.severity === severity)) return severity;\n }\n return null;\n}\n\n/**\n * Truncates a string in the middle if it exceeds maxLen.\n * Example: \"very-long-package-name\" -> \"very-lo…e-name\"\n */\nexport function middleTruncate(str: string, maxLen: number): string {\n if (str.length <= maxLen) return str;\n const ellipsis = '…';\n const charsToShow = maxLen - ellipsis.length;\n const frontChars = Math.ceil(charsToShow / 2);\n const backChars = Math.floor(charsToShow / 2);\n return str.slice(0, frontChars) + ellipsis + str.slice(-backChars);\n}\n\n/** Formats dependents as \"first +N\" if multiple. */\nexport function formatDependents(dependents: string[]): string {\n if (dependents.length === 0) return '';\n if (dependents.length === 1) return dependents[0];\n return `${dependents[0]} +${dependents.length - 1}`;\n}\n","/**\n * Extract the indented lines of a top-level YAML block (e.g. `overrides:`).\n * Stops at the next non-indented, non-empty line. Comment lines are skipped.\n */\nfunction yamlBlockLines(content: string, key: string): string[] {\n const lines: string[] = [];\n let inBlock = false;\n\n for (const line of content.split('\\n')) {\n if (new RegExp(`^${key}:\\\\s*$`).test(line)) {\n inBlock = true;\n continue;\n }\n if (!inBlock) continue;\n\n const trimmed = line.trim();\n if (trimmed.startsWith('#')) continue;\n // End of block: non-indented non-empty line (next top-level key)\n if (trimmed !== '' && !line.startsWith(' ') && !line.startsWith('\\t')) break;\n lines.push(line);\n }\n\n return lines;\n}\n\n/**\n * Parse a top-level YAML block of flat `key: value` entries into a record.\n * Quotes around keys and values are stripped.\n */\nexport function parseYamlBlockMap(content: string, key: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of yamlBlockLines(content, key)) {\n const match = line.match(/^\\s+(.+?):\\s+['\"]?([^'\"]+)['\"]?\\s*$/);\n if (match) {\n result[match[1].replace(/^['\"]|['\"]$/g, '')] = match[2];\n }\n }\n return result;\n}\n\n/**\n * Parse a top-level YAML block of `- item` list entries into an array.\n */\nexport function parseYamlBlockList(content: string, key: string): string[] {\n const items: string[] = [];\n for (const line of yamlBlockLines(content, key)) {\n const trimmed = line.trim();\n if (trimmed.startsWith('- ')) items.push(trimmed.slice(2).trim());\n }\n return items;\n}\n","/**\n * Contributions service for sync CLI.\n *\n * Upstream-side (cella): based on the configured `forks`, lets the user pick a\n * single fork, pulls its `pullBranch` and builds a clean local `contrib/<fork>`\n * branch with only that fork's contributed files. Then shows an interactive TUI\n * to review and adopt individual files into the working tree.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport {\n createPrompt,\n isDownKey,\n isEnterKey,\n isSpaceKey,\n isUpKey,\n useKeypress,\n useMemo,\n usePagination,\n useState,\n} from '@inquirer/core';\nimport { select } from '@inquirer/prompts';\nimport type { FileStatus, RuntimeConfig } from '../config/types';\nimport pc from '../utils/colors';\nimport { DEFAULT_BRANCH, loadConfig } from '../utils/config';\nimport { gitDiffFile, openDiffInBrowser } from '../utils/diff';\nimport { createSpinner, DIVIDER, spinnerFail, spinnerSuccess, warningMark, writeStdout } from '../utils/display';\nimport { getCurrentBranch, git, removeFileFromWorktree, restoreWorktreeFromRef } from '../utils/git';\nimport { buildContribBranch, countDetection, detectContributableFiles } from './contrib-core';\nimport { printNoForksHint, resolveForkBasePath, type ValidatedFork, validateForkPath } from './fork-utils';\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\ninterface ContribItem {\n /** File path relative to repo root */\n path: string;\n /** Local contrib branch ref (e.g., contrib/myfork) */\n ref: string;\n /** True if adopting this means deleting the file in cella */\n deleted: boolean;\n /** True if the file does not exist in cella yet (adopting it creates a new file) */\n created?: boolean;\n /** Analyzer status from cella's POV (behind = fork ahead, diverged = both changed) */\n status?: FileStatus;\n /** Relative date of the fork's change (e.g. '3 days ago') */\n changedAt?: string;\n /** Unix epoch seconds of the fork's change, for sorting */\n changedTs?: number;\n /** Lines added in the fork vs cella base (null for binary files) */\n additions?: number | null;\n /** Lines removed in the fork vs cella base (null for binary files) */\n deletions?: number | null;\n /** Whether file is selected for acceptance */\n checked: boolean;\n}\n\ninterface ContribPromptConfig {\n message: string;\n items: ContribItem[];\n /** Name of the fork being reviewed (used to label diffs cella/ vs <fork>/) */\n forkName: string;\n /** Base ref the contrib branches were built on (for diffing) */\n baseRef: string;\n /** Repo path where contrib branches live */\n cwd: string;\n pageSize?: number;\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\n/**\n * Open a browser diff for a contrib file (cella base vs the fork's version).\n * Returns the written page path, or null when the file has no changes.\n */\nasync function showContribDiff(\n item: ContribItem,\n baseRef: string,\n cwd: string,\n forkName: string,\n): Promise<string | null> {\n const patch = gitDiffFile(cwd, `${baseRef}..${item.ref}`, item.path);\n if (patch.length === 0) return null;\n return openDiffInBrowser(patch.toString(), { filePath: item.path, srcLabel: 'cella', dstLabel: forkName }, cwd);\n}\n\nfunction shouldApplyContributionsUnstaged(repoPath: string): boolean {\n return JSON.parse(readFileSync(join(repoPath, 'package.json'), 'utf8')).name === 'cella';\n}\n\n// ── Custom prompt ────────────────────────────────────────────────────────────\n\n/**\n * Interactive prompt for reviewing contributed files.\n * Returns items selected for acceptance.\n */\nconst contribPrompt = createPrompt<ContribItem[], ContribPromptConfig>((config, done) => {\n const { pageSize = 20, baseRef, cwd, forkName } = config;\n\n const [items, setItems] = useState<ContribItem[]>(config.items);\n const [active, setActive] = useState(0);\n const [statusMsg, setStatusMsg] = useState('');\n const [promptStatus, setPromptStatus] = useState<'idle' | 'done'>('idle');\n\n const bounds = useMemo(() => {\n if (items.length === 0) return { first: 0, last: 0 };\n return { first: 0, last: items.length - 1 };\n }, [items]);\n\n useKeypress(async (key) => {\n if (items.length === 0) {\n if (isEnterKey(key) || key.name === 'q') {\n setPromptStatus('done');\n done([]);\n }\n return;\n }\n\n // q = quit\n if (key.name === 'q') {\n setPromptStatus('done');\n done([]);\n return;\n }\n\n // Enter = accept selected\n if (isEnterKey(key)) {\n const selected = items.filter((i) => i.checked);\n if (selected.length === 0) {\n setStatusMsg('select files with space first, or q to quit');\n return;\n }\n setPromptStatus('done');\n done(selected);\n return;\n }\n\n // Navigation\n if (key.ctrl && isUpKey(key)) {\n setActive(bounds.first);\n setStatusMsg('');\n return;\n }\n if (key.ctrl && isDownKey(key)) {\n setActive(bounds.last);\n setStatusMsg('');\n return;\n }\n if (isUpKey(key)) {\n setActive(active <= bounds.first ? bounds.first : active - 1);\n setStatusMsg('');\n return;\n }\n if (isDownKey(key)) {\n setActive(active >= bounds.last ? bounds.last : active + 1);\n setStatusMsg('');\n return;\n }\n\n // Space = toggle selection\n if (isSpaceKey(key)) {\n setItems(items.map((item, i) => (i === active ? { ...item, checked: !item.checked } : item)));\n return;\n }\n\n // d = open diff in browser (non-blocking, the list stays up)\n if (key.name === 'd') {\n try {\n const pagePath = await showContribDiff(items[active], baseRef, cwd, forkName);\n setStatusMsg(pagePath ? `opened ${items[active].path} in browser` : `no changes for ${items[active].path}`);\n } catch (error) {\n setStatusMsg(`diff failed: ${error instanceof Error ? error.message : 'unknown error'}`);\n }\n return;\n }\n\n // a = toggle all (select all, or deselect all if already all selected)\n if (key.name === 'a') {\n const allChecked = items.every((item) => item.checked);\n setItems(items.map((item) => ({ ...item, checked: !allChecked })));\n setStatusMsg(allChecked ? 'deselected all' : 'selected all');\n return;\n }\n });\n\n // Render: done state\n if (promptStatus === 'done') {\n const checked = items.filter((i) => i.checked);\n if (checked.length > 0) {\n return `${pc.green('✓')} ${checked.length} files accepted`;\n }\n return `${pc.green('✓')} done`;\n }\n\n // Render: empty\n if (items.length === 0) {\n return `${pc.green('✓')} no contributions — press enter`;\n }\n\n // Render: paginated list\n const checkedCount = items.filter((i) => i.checked).length;\n\n const page = usePagination({\n items,\n active,\n renderItem({ item, isActive }) {\n const checkbox = item.checked ? pc.green('●') : pc.dim('○');\n const cursor = isActive ? pc.cyan('❯') : ' ';\n const newLabel = item.created ? pc.yellow(' · not in cella') : '';\n const delLabel = item.deleted ? pc.yellow(' [del]') : '';\n const statusTag = item.status === 'diverged' ? pc.yellow(' ⚠ diverged') : '';\n const dateLabel = item.changedAt ? pc.dim(` · ${item.changedAt}`) : '';\n const line = `${cursor} ${checkbox} ${item.path}${delLabel}${statusTag}${newLabel}${dateLabel}`;\n return isActive ? pc.cyan(line) : line;\n },\n pageSize,\n loop: false,\n });\n\n const countInfo =\n checkedCount > 0 ? `${items.length} files, ${pc.green(`${checkedCount} selected`)}` : `${items.length} files`;\n const header = `${pc.cyan('⬇')} ${config.message} ${pc.dim(`(${countInfo})`)}`;\n\n const keys: [string, string][] = [\n ['↑↓', 'navigate'],\n ['d', 'diff in browser'],\n ['a', '(de)select all'],\n ['space', 'select'],\n ['⏎', 'accept'],\n ['q', 'quit'],\n ];\n const helpLine = keys.map(([k, a]) => `${pc.bold(k)} ${pc.dim(a)}`).join(pc.dim(' · '));\n\n const statusLine = statusMsg ? ` ${pc.dim(statusMsg)}` : '';\n\n const lines = [header, page, statusLine, helpLine].filter(Boolean).join('\\n').trimEnd();\n return `${lines}\\x1B[?25l`;\n});\n\n// ── Fork pulling ─────────────────────────────────────────────────────────────\n\n/**\n * Fetch a fork's pullBranch into cella's object store and return the commit sha.\n */\nasync function fetchForkBranch(cellaPath: string, fetchSource: string, pullBranch: string): Promise<string> {\n await git(['fetch', fetchSource, pullBranch], cellaPath);\n return git(['rev-parse', 'FETCH_HEAD'], cellaPath);\n}\n\n/** Short sha + relative date of the fork's committed pullBranch HEAD (for the comparison banner). */\nasync function forkRefMeta(cellaPath: string, forkRef: string): Promise<{ sha: string; date: string }> {\n const out = await git(['log', '-1', '--format=%h%x09%cr', forkRef], cellaPath, { ignoreErrors: true });\n const [sha = forkRef.slice(0, 7), date = 'unknown'] = out.split('\\t');\n return { sha, date };\n}\n\n/**\n * Lines added/removed per file between cella base and the contrib branch.\n * Binary files report null. Used to enrich `--json` output for triage.\n */\nasync function diffStat(\n cellaPath: string,\n baseRef: string,\n ref: string,\n): Promise<Map<string, { additions: number | null; deletions: number | null }>> {\n const out = await git(['diff', '--numstat', `${baseRef}..${ref}`], cellaPath, { ignoreErrors: true });\n const stat = new Map<string, { additions: number | null; deletions: number | null }>();\n for (const line of out.split('\\n')) {\n if (!line.trim()) continue;\n const [a, d, ...rest] = line.split('\\t');\n const path = rest.join('\\t');\n if (!path) continue;\n stat.set(path, {\n additions: a === '-' ? null : Number(a),\n deletions: d === '-' ? null : Number(d),\n });\n }\n return stat;\n}\n\n// ── Main entry ───────────────────────────────────────────────────────────────\n\n/**\n * Run the contributions service.\n *\n * Based on the configured `forks`, lets the user select one or more forks,\n * pulls each fork's `pullBranch`, builds clean local `contrib/<fork>` branches,\n * then presents an interactive TUI to review and adopt individual files.\n */\nexport async function runContributions(config: RuntimeConfig): Promise<void> {\n const forks = config.forks ?? [];\n\n if (forks.length === 0) {\n printNoForksHint('add forks to pull contributions from:');\n return;\n }\n\n // Compare forks against cella's currently checked-out branch, not a fixed\n // configured branch, so contributions reflect the branch you're working on.\n const baseRef = await getCurrentBranch(config.forkPath);\n\n // Warn when not on cella's base branch. The comparison is a 3-way analysis against\n // merge-base(baseRef, fork), so a long-lived feature branch has an older merge-base\n // than 'main' and may surface extra 'diverged' files that would show clean from main.\n if (baseRef !== DEFAULT_BRANCH) {\n console.info(\n `${warningMark} ${pc.yellow(`not on base branch '${DEFAULT_BRANCH}'`)} ${pc.dim(`comparing forks against '${baseRef}'`)}`,\n );\n console.info(\n ` ${pc.dim(`older merge-base may show extra 'diverged' files; switch to '${DEFAULT_BRANCH}' for the cleanest result`)}`,\n );\n console.info('');\n }\n\n const forkBasePath = await resolveForkBasePath(config.forkPath);\n const validated = forks.map((fork) => validateForkPath(fork, forkBasePath));\n const validForks = validated.filter((v) => v.valid);\n\n // Select a single fork to pull from\n let selectedFork: ValidatedFork | undefined;\n if (config.fork) {\n const match = validated.find((v) => v.fork.name === config.fork);\n if (!match?.valid) {\n console.error(pc.red(`fork '${config.fork}' not found or invalid in config`));\n return;\n }\n selectedFork = match;\n } else if (config.list || config.json || config.diff) {\n // Non-interactive: require an explicit --fork when multiple forks are configured\n if (validForks.length === 0) {\n console.error(pc.red('no valid forks configured'));\n return;\n }\n if (validForks.length > 1) {\n console.error(pc.red('multiple forks configured; pass --fork <name> to choose one'));\n return;\n }\n selectedFork = validForks[0];\n } else {\n const choices = validated.map((v) => ({\n value: v.fork.name,\n name: v.valid\n ? `${v.fork.name} ${pc.dim(`[${v.fork.pullBranch}] ${v.fork.localPath}`)}`\n : `${v.fork.name} ${pc.dim(v.fork.localPath)}`,\n disabled: v.valid ? false : (v.error ?? 'invalid'),\n }));\n const picked = await select<string>({\n message: 'select fork to pull contributions from:',\n choices,\n loop: false,\n });\n selectedFork = validated.find((v) => v.fork.name === picked);\n }\n\n if (!selectedFork) {\n console.info(pc.dim('no fork selected.'));\n return;\n }\n\n const { fork, resolvedPath } = selectedFork;\n const forkName = fork.name;\n\n // Pull the fork and build a clean contrib/<fork> branch\n createSpinner('pulling fork contributions...');\n const allItems: ContribItem[] = [];\n let forkBanner: { pullBranch: string; sha: string; date: string } | null = null;\n\n try {\n // Prefer the fork's remote (authoritative committed ref) over the local clone.\n const fetchSource = fork.remoteUrl ?? resolvedPath;\n const forkRef = await fetchForkBranch(config.forkPath, fetchSource, fork.pullBranch);\n const meta = await forkRefMeta(config.forkPath, forkRef);\n forkBanner = { pullBranch: fork.pullBranch, sha: meta.sha, date: meta.date };\n\n // Read the fork's own owned folders so its fork-specific modules aren't offered back\n let forkTerritory: string[] = [];\n try {\n const forkConfig = await loadConfig(resolvedPath);\n forkTerritory = forkConfig.overrides?.ignored ?? [];\n } catch {\n // Fork may not have a cella/cella.config.ts — no extra territory to exclude\n }\n\n const detection = await detectContributableFiles(config.forkPath, baseRef, forkRef, config, forkTerritory);\n if (countDetection(detection) > 0) {\n const { branch, appliedFiles } = await buildContribBranch(config.forkPath, baseRef, forkRef, detection, forkName);\n if (appliedFiles.length > 0) {\n const stat = await diffStat(config.forkPath, baseRef, branch);\n const metaByPath = new Map(detection.files.map((f) => [f.path, f]));\n for (const path of [...detection.modified, ...detection.created]) {\n const fileMeta = metaByPath.get(path);\n allItems.push({\n path,\n ref: branch,\n deleted: false,\n created: fileMeta?.kind === 'created',\n status: fileMeta?.status,\n changedAt: fileMeta?.changedAt,\n changedTs: fileMeta?.changedTs,\n additions: stat.get(path)?.additions ?? null,\n deletions: stat.get(path)?.deletions ?? null,\n checked: false,\n });\n }\n for (const path of detection.deleted) {\n const fileMeta = metaByPath.get(path);\n allItems.push({\n path,\n ref: branch,\n deleted: true,\n status: fileMeta?.status,\n changedAt: fileMeta?.changedAt,\n changedTs: fileMeta?.changedTs,\n additions: stat.get(path)?.additions ?? null,\n deletions: stat.get(path)?.deletions ?? null,\n checked: false,\n });\n }\n }\n }\n } catch (error) {\n spinnerFail(`failed to pull ${forkName}`);\n console.info(pc.red(` ✗ ${error instanceof Error ? error.message : 'unknown error'}`));\n return;\n }\n\n if (allItems.length === 0) {\n spinnerSuccess('no contributions found');\n return;\n }\n\n // Sort by most recent fork change first (undated files last), path as tie-breaker,\n // so the top of the list shows where the fork last drifted (further) apart.\n allItems.sort((a, b) => (b.changedTs ?? 0) - (a.changedTs ?? 0) || a.path.localeCompare(b.path));\n\n spinnerSuccess(`${allItems.length} files from ${forkName}`);\n\n // Make the comparison basis explicit: the fork is compared at its committed pullBranch HEAD,\n // not its working tree, so uncommitted fork edits never appear here. Skipped for --list/--diff\n // so their stdout stays clean for machine parsing.\n if (!config.list && !config.diff && forkBanner) {\n console.info(\n ` ${pc.dim(`${forkName}: comparing committed '${forkBanner.pullBranch}' @ ${forkBanner.sha} (${forkBanner.date}) — uncommitted fork changes are not included`)}`,\n );\n }\n\n // Print the unified diff for a single file, then exit (tooling/agent usage).\n if (config.diff) {\n const matches = allItems.filter((i) => i.path === config.diff);\n if (matches.length === 0) {\n console.error(pc.red(`no contribution found for path: ${config.diff}`));\n process.exitCode = 1;\n return;\n }\n for (const item of matches) {\n const diff = gitDiffFile(config.forkPath, `${baseRef}..${item.ref}`, item.path, { dstPrefix: forkName });\n writeStdout(diff.toString());\n }\n return;\n }\n\n // Machine-readable JSON output for tooling/agent usage\n if (config.json) {\n const out = allItems.map((item) => ({\n fork: forkName,\n path: item.path,\n status: item.status ?? null,\n kind: item.deleted ? 'deleted' : 'modified',\n changedAt: item.changedAt ?? null,\n changedTs: item.changedTs ?? null,\n additions: item.additions ?? null,\n deletions: item.deletions ?? null,\n }));\n writeStdout(JSON.stringify(out, null, 2));\n return;\n }\n\n // Non-interactive mode: output enriched list for LLM/agent usage.\n // Columns are tab-separated: fork, status, kind, changedAt, path.\n // Note: status reflects the fork's committed pullBranch HEAD vs cella's base\n // (behind = fork ahead, diverged = both changed), not the fork's working tree.\n if (config.list) {\n for (const item of allItems) {\n const status = item.status ?? 'behind';\n const kind = item.deleted ? 'deleted' : 'modified';\n const changedAt = item.changedAt ?? '-';\n console.info(`${forkName}\\t${status}\\t${kind}\\t${changedAt}\\t${item.path}`);\n }\n return;\n }\n\n console.info();\n console.info(DIVIDER);\n\n // Run interactive prompt\n const selected = await contribPrompt({\n message: `contributions from ${forkName}`,\n items: allItems,\n forkName,\n baseRef,\n cwd: config.forkPath,\n pageSize: 20,\n });\n\n if (selected.length === 0) {\n console.info();\n return;\n }\n\n // Apply selected files into the working tree\n createSpinner(`applying ${selected.length} files...`);\n const applyUnstaged = shouldApplyContributionsUnstaged(config.forkPath);\n\n let applied = 0;\n const errors: string[] = [];\n\n for (const item of selected) {\n try {\n // Reject paths with traversal components (CWE-22)\n if (item.path.includes('..') || item.path.startsWith('/')) {\n errors.push(`${item.path}: rejected (path traversal)`);\n continue;\n }\n if (item.deleted) {\n if (applyUnstaged) {\n await removeFileFromWorktree(config.forkPath, item.path);\n } else {\n await git(['rm', '-f', '--', item.path], config.forkPath, { ignoreErrors: true });\n }\n } else {\n if (applyUnstaged) {\n await restoreWorktreeFromRef(config.forkPath, item.ref, item.path);\n } else {\n await git(['checkout', item.ref, '--', item.path], config.forkPath);\n }\n }\n applied++;\n } catch (error) {\n errors.push(`${item.path}: ${error instanceof Error ? error.message : 'unknown error'}`);\n }\n }\n\n if (errors.length > 0) {\n spinnerFail(`applied ${applied}/${selected.length} files (${errors.length} errors)`);\n for (const err of errors) {\n console.info(pc.red(` ✗ ${err}`));\n }\n } else {\n spinnerSuccess(`applied ${applied} files ${pc.dim(applyUnstaged ? '(unstaged)' : '(staged)')}`);\n }\n\n // No per-file summary: the applied files are visible in the IDE's source control view.\n console.info();\n console.info(\n pc.dim(\n applyUnstaged\n ? ' files are unstaged — review, stage what you want, and commit when ready'\n : ' files are staged — review and commit when ready',\n ),\n );\n console.info();\n}\n","/**\n * Shared contribution engine.\n *\n * Cella (upstream) pulls a fork's branch and detects which files the fork\n * changed, created, or deleted relative to cella's base branch. It then builds\n * a clean local `contrib/<fork>` branch — built on top of the base branch with\n * only the fork's file overlays — so the changes can be reviewed and adopted\n * without a working-tree checkout.\n *\n * The fork's blobs are read directly from the fetched ref (already in cella's\n * object store), never from the filesystem.\n */\n\nimport { dirname, join, resolve } from 'node:path';\nimport type { CellaCliConfig, FileStatus } from '../config/types';\nimport { git } from '../utils/git';\nimport { isIgnored, isPinned, isUnderAnyFolder } from '../utils/overrides';\nimport { analyzeRefs, enrichChangeInfo } from './analyze-core';\n\n/** A single contributable file with classification and metadata. */\nexport interface ContribFile {\n /** File path relative to repo root */\n path: string;\n /** How adopting this file changes cella */\n kind: 'modified' | 'created' | 'deleted';\n /** Analyzer status from cella's POV (behind = fork ahead, diverged = both changed) */\n status: FileStatus;\n /** Relative date of the fork's change (e.g. '3 days ago') */\n changedAt?: string;\n /** Unix epoch seconds of the fork's change, for sorting */\n changedTs?: number;\n}\n\n/** Files a fork contributes relative to the base branch. */\nexport interface ContribDetection {\n /** Files changed in fork that also exist in base */\n modified: string[];\n /** New fork files in directories that exist in base (sibling heuristic) */\n created: string[];\n /** Files that exist in base but were removed in fork */\n deleted: string[];\n /** Enriched per-file metadata for the union of the above */\n files: ContribFile[];\n}\n\n/**\n * List all files tracked at a ref.\n */\nasync function listFilesAtRef(repoPath: string, ref: string): Promise<Set<string>> {\n const raw = await git(['ls-tree', '-r', '--name-only', ref], repoPath);\n return new Set(raw.split('\\n').filter(Boolean));\n}\n\n/**\n * Detect the files a fork contributes relative to cella's base branch.\n *\n * Uses a merge-base 3-way analysis (cella = local, fork = incoming) so the\n * result distinguishes fork-ahead changes from cella's own drift. Only files\n * where the fork is ahead (status `behind`) or both sides changed (`diverged`)\n * are contributable.\n *\n * @param repoPath - Cella repo path (where the fork ref has been fetched)\n * @param baseRef - Cella's base branch ref (e.g. 'development')\n * @param forkRef - Fetched fork commit (e.g. a resolved FETCH_HEAD sha)\n * @param config - Cella's config, used to exclude ignored/pinned files\n * @param forkTerritory - Paths the fork owns (from the fork's own\n * `ignored` list); excluded so fork-specific modules aren't offered back\n */\nexport async function detectContributableFiles(\n repoPath: string,\n baseRef: string,\n forkRef: string,\n config: CellaCliConfig,\n forkTerritory: string[] = [],\n): Promise<ContribDetection> {\n // Common ancestor for 3-way comparison; fall back to baseRef if histories are unrelated\n const mergeBase = (await git(['merge-base', baseRef, forkRef], repoPath, { ignoreErrors: true })).trim() || baseRef;\n\n const predicates = {\n isIgnored: (path: string) => isIgnored(path, config) || isUnderAnyFolder(path, forkTerritory),\n isPinned: (path: string) => isPinned(path, config),\n };\n\n // local = cella (baseRef), incoming = fork (forkRef)\n const analyzed = await analyzeRefs(repoPath, baseRef, forkRef, mergeBase, predicates);\n await enrichChangeInfo(repoPath, analyzed, mergeBase, baseRef, forkRef);\n\n // Base directory set for the sibling heuristic on created files.\n // Seed with '.' because the repo root always exists in cella, so new fork\n // files at the root (e.g. a shared config) are offered rather than silently skipped.\n const baseFiles = await listFilesAtRef(repoPath, baseRef);\n const baseDirs = new Set<string>(['.']);\n for (const f of baseFiles) {\n let dir = dirname(f);\n while (dir !== '.') {\n baseDirs.add(dir);\n dir = dirname(dir);\n }\n }\n\n const files: ContribFile[] = [];\n for (const file of analyzed) {\n // Only files where the fork is ahead of cella are contributable\n if (file.status !== 'behind' && file.status !== 'diverged') continue;\n if (file.isIgnored || file.isPinned) continue;\n\n const inCella = file.existsInFork; // local side\n const inFork = file.existsInUpstream; // incoming side\n\n let kind: ContribFile['kind'];\n if (inCella && !inFork) {\n kind = 'deleted';\n } else if (!inCella && inFork) {\n // New fork file: only offer it when its directory already exists in cella,\n // so fork-specific modules don't flood the list (territory handles the rest)\n if (!baseDirs.has(dirname(file.path))) continue;\n kind = 'created';\n } else {\n kind = 'modified';\n }\n\n // Fork-side change date: 'behind' stores it in changedAt, 'diverged' in upstreamChangedAt\n const changedAt = file.status === 'diverged' ? file.upstreamChangedAt : file.changedAt;\n const changedTs = file.status === 'diverged' ? file.upstreamChangedTs : file.changedTs;\n files.push({ path: file.path, kind, status: file.status, changedAt, changedTs });\n }\n\n return {\n modified: files.filter((f) => f.kind === 'modified').map((f) => f.path),\n created: files.filter((f) => f.kind === 'created').map((f) => f.path),\n deleted: files.filter((f) => f.kind === 'deleted').map((f) => f.path),\n files,\n };\n}\n\n/** Total number of files in a detection result. */\nexport function countDetection(detection: ContribDetection): number {\n return detection.modified.length + detection.created.length + detection.deleted.length;\n}\n\n/**\n * Read mode and blob hash for a file at a ref.\n * Returns null if the path is not a regular blob at the ref.\n */\nasync function readBlobInfo(\n repoPath: string,\n ref: string,\n filePath: string,\n): Promise<{ mode: string; hash: string } | null> {\n const line = await git(['ls-tree', ref, '--', filePath], repoPath, { ignoreErrors: true });\n if (!line) return null;\n // Format: \"<mode> <type> <hash>\\t<path>\"\n const match = line.match(/^(\\d{6}) (\\w+) ([0-9a-f]+)\\t/);\n if (!match) return null;\n const [, mode, type, hash] = match;\n if (type !== 'blob') return null;\n // Only allow regular (100644) and executable (100755) file modes; skip symlinks/gitlinks\n if (mode !== '100644' && mode !== '100755') return null;\n return { mode, hash };\n}\n\n/**\n * Build a clean local `contrib/<fork>` branch from a fork's contributed files.\n *\n * The branch is created on top of `baseRef` with only the fork's file overlays\n * applied via a temporary index — the working tree is never touched.\n *\n * @returns The branch name and number of files applied.\n */\nexport async function buildContribBranch(\n repoPath: string,\n baseRef: string,\n forkRef: string,\n detection: ContribDetection,\n forkName: string,\n): Promise<{ branch: string; appliedFiles: string[] }> {\n const branch = `contrib/${forkName}`;\n // Resolve the actual git dir: in a linked worktree `.git` is a pointer file, and the\n // worktree's git dir lives under the main checkout's `.git/worktrees/<name>`.\n const gitDir = resolve(repoPath, await git(['rev-parse', '--git-dir'], repoPath));\n const tmpIndex = join(gitDir, `tmp-contrib-index-${forkName.replace(/[^\\w.-]/g, '_')}`);\n const indexEnv = { GIT_INDEX_FILE: tmpIndex };\n\n try {\n // Seed the temp index with cella's base tree\n await git(['read-tree', baseRef], repoPath, { env: indexEnv });\n\n const appliedFiles: string[] = [];\n\n // Overlay modified + created fork files (blobs already in object store via fetch)\n for (const filePath of [...detection.modified, ...detection.created]) {\n const blob = await readBlobInfo(repoPath, forkRef, filePath);\n if (!blob) continue;\n await git(\n ['update-index', '--add', '--replace', '--cacheinfo', `${blob.mode},${blob.hash},${filePath}`],\n repoPath,\n {\n env: indexEnv,\n },\n );\n appliedFiles.push(filePath);\n }\n\n // Remove deleted files from the index\n for (const filePath of detection.deleted) {\n await git(['update-index', '--remove', filePath], repoPath, { env: indexEnv, ignoreErrors: true });\n appliedFiles.push(`(deleted) ${filePath}`);\n }\n\n if (appliedFiles.length === 0) {\n return { branch, appliedFiles };\n }\n\n // Write tree and commit on top of base\n const treeHash = await git(['write-tree'], repoPath, { env: indexEnv });\n const parentHash = await git(['rev-parse', baseRef], repoPath);\n const commitBody = appliedFiles.map((f) => `- ${f}`).join('\\n');\n const commitMessage = `contrib(${forkName}): ${appliedFiles.length} files\\n\\n${commitBody}`;\n const commitHash = await git(['commit-tree', treeHash, '-p', parentHash, '-m', commitMessage], repoPath);\n\n // Create/update the local branch ref without checkout\n await git(['update-ref', `refs/heads/${branch}`, commitHash], repoPath);\n\n return { branch, appliedFiles };\n } finally {\n try {\n const { unlinkSync } = await import('node:fs');\n unlinkSync(tmpIndex);\n } catch {\n // Best effort\n }\n }\n}\n","/**\n * Shared helpers for the fork-aware services (`forks` and `contributions`).\n */\n\nimport { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport type { ForkConfig } from '../config/types';\nimport pc from '../utils/colors';\nimport { git } from '../utils/git';\nimport { CONFIG_FILE } from '../utils/managed-files';\n\n/**\n * Base directory that relative fork `localPath` values resolve against.\n *\n * A `localPath` like `../my-app` is written relative to the repository's main checkout. When\n * the CLI runs inside a linked worktree (e.g. `.claude/worktrees/x`), resolving against the\n * worktree would point inside the worktrees directory, so resolve against the main repository\n * root: the parent of the shared git common dir. Falls back to `repoPath` outside a repository.\n */\nexport async function resolveForkBasePath(repoPath: string): Promise<string> {\n const commonDir = await git(['rev-parse', '--git-common-dir'], repoPath, { ignoreErrors: true });\n return commonDir ? dirname(resolve(repoPath, commonDir)) : repoPath;\n}\n\n/** A fork config paired with its validation result. */\nexport interface ValidatedFork {\n fork: ForkConfig;\n resolvedPath: string;\n valid: boolean;\n error?: string;\n}\n\n/**\n * Validate a fork's local path resolves safely and points at a git repository.\n *\n * @param requireConfig when true, the fork must also contain a `cella/cella.config.ts`.\n */\nexport function validateForkPath(fork: ForkConfig, basePath: string, requireConfig = false): ValidatedFork {\n const resolvedPath = resolve(basePath, fork.localPath);\n\n // Validate resolved path doesn't escape the parent directory via traversal (CWE-22)\n if (!resolvedPath.startsWith(resolve(basePath, '..'))) {\n return { fork, resolvedPath, valid: false, error: 'path resolves outside parent directory' };\n }\n if (!existsSync(resolvedPath)) return { fork, resolvedPath, valid: false, error: 'path does not exist' };\n if (!existsSync(`${resolvedPath}/.git`)) return { fork, resolvedPath, valid: false, error: 'not a git repository' };\n if (requireConfig && !existsSync(`${resolvedPath}/${CONFIG_FILE}`)) {\n return { fork, resolvedPath, valid: false, error: `missing ${CONFIG_FILE}` };\n }\n\n return { fork, resolvedPath, valid: true };\n}\n\n/**\n * Print the \"no forks configured\" empty-state with a config example.\n *\n * @param action a short dim line describing what forks enable (e.g. 'add forks to your config:').\n */\nexport function printNoForksHint(action: string): void {\n console.info(pc.yellow('no forks configured in cella/cella.config.ts'));\n console.info(pc.dim(action));\n console.info(pc.dim(` forks: [{ name: 'my-app', localPath: '../my-app', pullBranch: 'development' }]`));\n}\n","/**\n * Forks service for sync CLI v2.\n *\n * Allows syncing to multiple local fork repositories from an upstream template.\n * Selecting a fork immediately runs sync (+ packages if enabled), then returns to selection.\n */\n\nimport { resolve } from 'node:path';\nimport process from 'node:process';\nimport { Separator, select } from '@inquirer/prompts';\nimport type { ForkConfig, RuntimeConfig } from '../config/types';\nimport pc from '../utils/colors';\nimport { loadConfig, resolveUpstream } from '../utils/config';\nimport { getCommitInfo, getCurrentBranch, getStoredSyncRef, git } from '../utils/git';\nimport { printNoForksHint, resolveForkBasePath, validateForkPath } from './fork-utils';\nimport { runSyncCommand } from './sync';\n\n/** Status info gathered from a fork repository */\ninterface ForkStatus {\n branch: string;\n dirty: number;\n lastSync: { date: string; message: string } | null;\n}\n\n/**\n * Gather git status info for a fork: branch, dirty state, last sync.\n */\nasync function gatherForkStatus(forkPath: string): Promise<ForkStatus> {\n const [branch, porcelain, syncRef] = await Promise.all([\n getCurrentBranch(forkPath).catch(() => 'unknown'),\n git(['status', '--porcelain'], forkPath, { ignoreErrors: true }),\n getStoredSyncRef(forkPath),\n ]);\n\n const dirty = porcelain ? porcelain.split('\\n').filter(Boolean).length : 0;\n\n let lastSync: { date: string; message: string } | null = null;\n if (syncRef) {\n const commitInfo = await getCommitInfo(forkPath, syncRef).catch(() => null);\n lastSync = { date: commitInfo?.date ?? 'unknown', message: commitInfo?.message ?? '' };\n }\n\n return { branch, dirty, lastSync };\n}\n\n/**\n * Format a fork choice label with status info.\n */\nfunction formatForkChoice(name: string, status: ForkStatus | null): string {\n if (!status) return name;\n\n // Sync: date and truncated commit message.\n let syncPart: string;\n if (status.lastSync) {\n const msg =\n status.lastSync.message.length > 36 ? `${status.lastSync.message.slice(0, 36)}…` : status.lastSync.message;\n syncPart = pc.dim(`${status.lastSync.date}`);\n if (msg) syncPart += pc.dim(` '${msg}'`);\n } else {\n syncPart = pc.dim('never synced');\n }\n\n // Dirty state: only show if there are uncommitted changes\n const dirtyPart = status.dirty > 0 ? pc.yellow(`${status.dirty} uncommitted`) : '';\n\n const parts = [name, pc.dim(`[${status.branch}]`), syncPart];\n if (dirtyPart) parts.push(dirtyPart);\n\n return parts.join(pc.dim(' · '));\n}\n\n/**\n * Build fork choices with live status info gathered in parallel.\n */\nasync function buildForkChoices(\n forks: ForkConfig[],\n basePath: string,\n): Promise<Array<{ value: string; name: string; disabled?: string }>> {\n const validated = forks.map((fork) => validateForkPath(fork, basePath, true));\n\n // Gather status for all valid forks in parallel\n const statusEntries = await Promise.all(\n validated\n .filter((v) => v.valid)\n .map(async (v) => {\n const status = await gatherForkStatus(v.resolvedPath);\n return { path: v.fork.localPath, status };\n }),\n );\n const statusMap = new Map(statusEntries.map((e) => [e.path, e.status]));\n\n return validated.map((v) => {\n if (!v.valid) {\n return {\n value: v.fork.localPath,\n name: `${v.fork.name} ${pc.dim(v.fork.localPath)}`,\n disabled: v.error,\n };\n }\n return {\n value: v.fork.localPath,\n name: formatForkChoice(v.fork.name, statusMap.get(v.fork.localPath) ?? null),\n };\n });\n}\n\n/**\n * Sync a single fork by running the same command flow the fork owner would run locally.\n */\nasync function syncFork(config: RuntimeConfig, fork: ForkConfig, forkPath: string): Promise<void> {\n console.info();\n console.info(pc.cyan(`syncing to ${fork.name}...`));\n console.info(pc.dim(`path: ${forkPath}`));\n console.info();\n\n const forkConfig = await loadConfig(forkPath);\n\n // Build runtime config for the fork.\n const { branchRef } = resolveUpstream(forkConfig.settings);\n const upstreamRef = branchRef;\n\n const forkRuntimeConfig: RuntimeConfig = {\n ...forkConfig,\n forkPath,\n upstreamRef,\n service: 'sync',\n logFile: config.logFile,\n list: false,\n json: false,\n verbose: config.verbose,\n hard: config.hard,\n };\n\n await runSyncCommand(forkRuntimeConfig);\n}\n\n/**\n * Run the forks service.\n *\n * Lists configured forks. Selecting a fork runs sync immediately,\n * then returns to the selection menu.\n */\nexport async function runForks(config: RuntimeConfig): Promise<void> {\n const forks = config.forks ?? [];\n\n if (forks.length === 0) {\n printNoForksHint('add forks to your config:');\n return;\n }\n\n // Non-interactive mode via --fork flag\n if (config.fork) {\n const match = forks.find((f) => f.name === config.fork);\n if (!match) {\n console.error(pc.red(`fork '${config.fork}' not found in config`));\n return;\n }\n const resolvedPath = resolve(await resolveForkBasePath(config.forkPath), match.localPath);\n await syncFork(config, match, resolvedPath);\n return;\n }\n\n // Interactive loop: select fork → sync → return to selection\n // Choices are rebuilt each iteration to reflect updated status\n const forkBasePath = await resolveForkBasePath(config.forkPath);\n while (true) {\n const choices = await buildForkChoices(forks, forkBasePath);\n const forkChoices = [...choices, new Separator('─'.repeat(40)), { value: '_exit', name: pc.dim('exit') }];\n\n const selectedPath = await select<string>({\n message: 'select fork to sync:',\n choices: forkChoices,\n loop: false,\n });\n\n if (selectedPath === '_exit') {\n process.exit(0);\n }\n\n const resolvedForkPath = resolve(forkBasePath, selectedPath);\n const selectedFork = forks.find((f) => f.localPath === selectedPath);\n if (!selectedFork) {\n console.error(pc.red(`fork '${selectedPath}' not found in config`));\n continue;\n }\n\n await syncFork(config, selectedFork, resolvedForkPath);\n\n console.info();\n }\n}\n","/**\n * Sync service for the cella CLI.\n *\n * Runs the merge engine directly in the fork (no worktree) so conflicts surface in the IDE, on\n * a fresh temporary branch cut from the trunk. The command is idempotent: if a run stops at\n * conflicts, resolve them and run `cella sync` again to finish the same merge.\n */\n\nimport { spawnSync } from 'node:child_process';\nimport { select } from '@inquirer/prompts';\nimport type { MergeResult, RuntimeConfig } from '../config/types';\nimport pc from '../utils/colors';\nimport {\n buildTemporarySyncBranch,\n DEFAULT_SYNC_PREFIX,\n isTemporarySyncBranch,\n resolveReleaseBase,\n} from '../utils/config';\nimport {\n createSpinner,\n printFlagWarnings,\n printMaskingPinWarning,\n printSummary,\n printSyncComplete,\n spinnerFail,\n spinnerSuccess,\n spinnerText,\n warningMark,\n writeLogFile,\n} from '../utils/display';\nimport { closePr, type GhPullRequest, ghAvailable, listOpenSyncPrs, mergePrSquash } from '../utils/gh';\nimport {\n assertClean,\n type CommitRangeEntry,\n commitSquash,\n countCommitsBetween,\n createBranchFrom,\n deleteBranch,\n flattenBranch,\n getCommitInfo,\n getConflictedFiles,\n getCurrentBranch,\n getMergeBase,\n getShortSha,\n getUpstreamStatus,\n isClean,\n listBranchMergeCommits,\n listCommitsBetween,\n mergeInProgress,\n pullFastForward,\n pushBranch,\n readManifestAtRef,\n readManifestBaseAtRef,\n readPackageVersionAtRef,\n stageAll,\n switchBranch,\n} from '../utils/git';\nimport { readSyncManifest } from '../utils/manifest';\nimport { runMergeEngine } from './merge-engine';\nimport { runPackages } from './packages';\n\n/** Context for the temporary branch a sync cycle runs on. */\ninterface TemporarySyncBranch {\n /** The freshly cut temporary branch, e.g. `cella/sync/20260702-1430`. */\n temporaryBranch: string;\n /** The trunk the branch was cut from and PRs land into (`releaseBase`, default `main`). */\n base: string;\n /** The branch the user was on before the cycle started (for cleanup on no-op). */\n startBranch: string;\n}\n\n/**\n * Make sure the trunk is current with its remote before a sync cycle cuts a branch from it.\n *\n * Fetches the trunk's upstream and reacts to how local compares:\n * - behind (fast-forwardable): fast-forward it so the branch is cut from the latest trunk.\n * - diverged (local commits the remote lacks *and* vice versa): abort with guidance, since\n * syncing onto a stale/diverged trunk produces a PR against an out-of-date base and avoidable\n * conflicts.\n * - ahead-only / up to date / no upstream (local-only repo): fine, just note it and continue.\n */\nasync function ensureBaseUpToDate(forkPath: string, base: string): Promise<void> {\n const { upstream, ahead, behind } = await getUpstreamStatus(forkPath);\n\n if (!upstream) {\n console.info(pc.dim(`'${base}' has no upstream — skipping the up-to-date check.`));\n return;\n }\n\n if (ahead > 0 && behind > 0) {\n throw new Error(\n `'${base}' has diverged from '${upstream}' (${ahead} ahead, ${behind} behind).\\n` +\n `Reconcile '${base}' with '${upstream}' first (e.g. rebase or reset it), then re-run sync.`,\n );\n }\n\n if (behind > 0) {\n console.info(pc.dim(`fast-forwarding '${base}' to '${upstream}' (${behind} behind)...`));\n await pullFastForward(forkPath);\n return;\n }\n\n if (ahead > 0) {\n console.info(pc.dim(`'${base}' is ${ahead} commit(s) ahead of '${upstream}' (unpushed) — continuing.`));\n }\n}\n\n/**\n * Cut a fresh temporary sync branch from the trunk.\n *\n * Switches to `releaseBase`, fast-forwards it, then creates `cella/sync/<stamp>` so the\n * merge lands on an isolated throwaway branch rather than a long-lived integration branch.\n */\nasync function setupTemporarySyncBranch(config: RuntimeConfig): Promise<TemporarySyncBranch> {\n const { forkPath, settings } = config;\n const base = resolveReleaseBase(settings);\n const startBranch = await getCurrentBranch(forkPath);\n\n console.info(pc.dim(`switching to '${base}' and updating...`));\n await switchBranch(forkPath, base);\n await ensureBaseUpToDate(forkPath, base);\n\n const temporaryBranch = buildTemporarySyncBranch();\n\n console.info(pc.dim(`creating temporary sync branch '${temporaryBranch}' from '${base}'...`));\n console.info();\n await createBranchFrom(forkPath, temporaryBranch, base);\n\n return { temporaryBranch, base, startBranch };\n}\n\n/**\n * Run the merge engine against the current branch (the core merge step).\n *\n * Performs the merge directly in the fork and leaves it staged: conflicted files keep their\n * markers for IDE 3-way resolution, everything else is resolved per the override rules. Called\n * by `runSyncCycle` and by the forks service.\n */\nexport async function runSync(\n config: RuntimeConfig,\n options?: {\n stagedBranch?: string;\n },\n): Promise<MergeResult> {\n createSpinner('starting sync...');\n\n const result = await runMergeEngine(config, {\n apply: true,\n onProgress: (message) => {\n spinnerText(message);\n },\n onStep: (label, detail) => {\n spinnerSuccess(label, detail);\n createSpinner('...');\n },\n });\n\n if (result.success) {\n spinnerSuccess();\n } else {\n spinnerFail('sync completed with conflicts');\n }\n\n // Print summary only (no file lists for sync)\n printSummary(result.summary, 'merge summary');\n\n // Surface pins that silently froze a file at the old upstream (no conflict, no type error)\n printMaskingPinWarning(result.files);\n\n // Write log file if requested\n if (config.logFile) {\n const logPath = writeLogFile(config.forkPath, result.files);\n console.info();\n console.info(pc.dim(`full file list written to: ${logPath}`));\n }\n\n const stagedBranch =\n options?.stagedBranch && result.conflicts.length === 0 && hasStagedSyncChanges(result)\n ? options.stagedBranch\n : undefined;\n printSyncComplete(result, { stagedBranch });\n\n printFlagWarnings({ hard: config.hard, unpinned: config.unpinned });\n\n return result;\n}\n\n/** Conventional PR title prefix required by release-please. */\nconst SYNC_PR_TITLE = 'chore: sync upstream cella';\n\n/** Most recent upstream commits listed in a sync PR body (mirrors the engine's fetch display cap). */\nconst PR_BODY_COMMIT_MAX = 50;\n\n/**\n * Build the sync commit subject, e.g. `chore: sync upstream cella v0.2.2 (4f7d87c)`.\n *\n * The upstream version comes from the manifest's release tag when tracking releases, else from\n * upstream's root package.json at the merged commit. Falls back to the bare title (+ short sha)\n * when a lookup fails, so committing never blocks on cosmetics.\n */\nasync function buildSyncCommitMessage(forkPath: string, upstreamRef: string): Promise<string> {\n const shortSha = await getShortSha(forkPath, upstreamRef).catch(() => '');\n if (!shortSha) return SYNC_PR_TITLE;\n\n const manifest = await readSyncManifest(forkPath);\n const version =\n manifest?.upstream.release ?? (await readPackageVersionAtRef(forkPath, upstreamRef).catch(() => null));\n return version ? `${SYNC_PR_TITLE} v${version.replace(/^v/, '')} (${shortSha})` : `${SYNC_PR_TITLE} ${shortSha}`;\n}\n\n/**\n * Qualify bare `#123` references in an upstream commit subject with the upstream repo slug.\n * Left bare, GitHub would auto-link them to the fork's own issue/PR #123 in the PR body.\n */\nfunction qualifyPrRefs(subject: string, repoSlug?: string): string {\n if (!repoSlug) return subject;\n return subject.replace(/(^|[^\\w/])#(\\d+)\\b/g, `$1${repoSlug}#$2`);\n}\n\n/** Inputs for {@link buildSyncPrBody}, recovered from the committed sync manifests. */\nexport interface SyncPrBodyInput {\n /** GitHub slug of the upstream repo, e.g. 'cellajs/cella'. */\n repoSlug?: string;\n /** Upstream version or release tag at the sync point (leading `v` optional). */\n version?: string | null;\n /** Previous upstream sync point (full sha), when known. */\n fromSha?: string | null;\n /** Upstream commit this sync moved to (full sha). */\n toSha: string;\n /** Upstream commits in the range, oldest first (possibly truncated to the newest N). */\n commits: CommitRangeEntry[];\n /** Total commits in the range (may exceed `commits.length` when truncated). */\n totalCount: number;\n}\n\n/** Render the sync PR body: where the sync moved to, plus the upstream commits it brought in. */\nexport function buildSyncPrBody(input: SyncPrBodyInput): string {\n const { repoSlug, version, fromSha, toSha, commits, totalCount } = input;\n const githubUrl = repoSlug ? `https://github.com/${repoSlug}` : undefined;\n const short = (sha: string) => sha.slice(0, 7);\n const commitRef = (sha: string) =>\n githubUrl ? `[\\`${short(sha)}\\`](${githubUrl}/commit/${sha})` : `\\`${short(sha)}\\``;\n\n const upstreamName = githubUrl ? `[${repoSlug}](${githubUrl})` : 'cella';\n const versionSuffix = version ? ` (v${version.replace(/^v/, '')})` : '';\n const lines = [`Syncs upstream ${upstreamName} to ${commitRef(toSha)}${versionSuffix}.`];\n\n if (totalCount > 0 && fromSha) {\n const compare = githubUrl ? ` ([compare](${githubUrl}/compare/${short(fromSha)}...${short(toSha)}))` : '';\n lines.push('', `**${totalCount} upstream commit${totalCount === 1 ? '' : 's'} since last sync**${compare}:`, '');\n if (totalCount > commits.length) lines.push(`- …${totalCount - commits.length} earlier commit(s) not shown`);\n for (const commit of commits) {\n lines.push(`- ${commitRef(commit.hash)} ${qualifyPrRefs(commit.message, repoSlug)}`);\n }\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/**\n * Build the PR body for a finished sync branch: the upstream commits between the trunk's last\n * recorded sync point and the one this branch moves to (both read from committed manifests, so\n * this works on the rerun that ships the branch, long after the merge engine ran).\n *\n * Returns undefined when the branch has no committed manifest — the caller falls back to `--fill`.\n */\nasync function buildSyncPrBodyForBranch(forkPath: string, base: string): Promise<string | undefined> {\n const manifest = await readManifestAtRef(forkPath, 'HEAD');\n if (!manifest) return undefined;\n\n const toSha = manifest.upstream.commit.toLowerCase();\n // The trunk's committed manifest is the previous sync point; merge-base covers forks whose\n // last sync predates the manifest. `refs/cella/last-sync` is no help here: the merge already\n // moved it to `toSha`.\n const fromSha =\n (await readManifestBaseAtRef(forkPath, base)) ?? (await getMergeBase(forkPath, base, toSha).catch(() => null));\n const version = manifest.upstream.release ?? (await readPackageVersionAtRef(forkPath, toSha).catch(() => null));\n\n const totalCount = fromSha ? await countCommitsBetween(forkPath, fromSha, toSha).catch(() => 0) : 0;\n const commits =\n fromSha && totalCount > 0\n ? await listCommitsBetween(forkPath, fromSha, toSha, {\n oldestFirst: true,\n skip: totalCount > PR_BODY_COMMIT_MAX ? totalCount - PR_BODY_COMMIT_MAX : 0,\n limit: PR_BODY_COMMIT_MAX,\n })\n : [];\n\n return buildSyncPrBody({ repoSlug: manifest.upstream.repo, version, fromSha, toSha, commits, totalCount });\n}\n\n/** Print the GitHub CLI command for opening the finished sync PR. */\nfunction printPrCreateStep(branch: string, base: string, title = SYNC_PR_TITLE): void {\n console.info(pc.dim(` gh pr create --base ${base} --head ${branch} --title \"${title}\" --fill`));\n}\n\n/** Print the \"push + open a PR\" steps for a sync branch whose merge is already committed. */\nfunction printShipSteps(temporaryBranch: string, base: string, title?: string): void {\n console.info(pc.dim(` git push -u origin ${temporaryBranch}`));\n printPrCreateStep(temporaryBranch, base, title);\n}\n\n/** Guidance shown after a fresh cycle stages a merge: re-run to finish and ship it. */\nfunction printFinishSteps(): void {\n console.info(pc.dim(' pnpm cella sync'));\n}\n\n/** Whether sync applied changes that need a finishing rerun. */\nfunction hasStagedSyncChanges(result: MergeResult): boolean {\n return result.files.some((file) => ['behind', 'diverged', 'renamed', 'ignored', 'pinned'].includes(file.status));\n}\n\n/** Extract the first URL from command output, usually the PR URL emitted by GitHub CLI. */\nfunction extractFirstUrl(output: string): string | undefined {\n return output.match(/https?:\\/\\/\\S+/)?.[0];\n}\n\n/**\n * Safety net run before a sync branch goes public: flatten away merge commits.\n *\n * The finishing rerun commits the sync as a single-parent commit (`commitSquash`), but a manual\n * `git commit` while the merge is staged records a two-parent merge commit instead. Upstream's\n * history isn't shared with `origin` (sync PRs are squash-merged), so such a commit makes the PR\n * list every upstream commit ever made — and that list grows with every upstream release.\n *\n * When the branch contains merge commits, rewrite it as one commit with identical content\n * (the PR diff is unchanged). Returns true if the branch was rewritten, so the caller can\n * force-push over a previously pushed version.\n */\nasync function flattenSyncBranch(forkPath: string, branch: string, base: string): Promise<boolean> {\n const mergeCommits = await listBranchMergeCommits(forkPath, base);\n if (mergeCommits.length === 0) return false;\n\n // The most recent merge's second parent is the upstream tip that was merged in.\n const message = await buildSyncCommitMessage(forkPath, `${mergeCommits[0]}^2`);\n\n console.info(\n pc.yellow(\n `'${branch}' contains ${mergeCommits.length} merge commit(s) — the PR would list the entire upstream history.`,\n ),\n );\n console.info(pc.dim(`flattening '${branch}' to a single commit (same content)...`));\n await flattenBranch(forkPath, base, message);\n return true;\n}\n\n/** Indent every line of `text` by two spaces, for nesting captured `gh` output under a message. */\nfunction indentLines(text: string): string {\n return text\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n}\n\n/**\n * Turn on GitHub auto-merge (squash) for the just-opened sync PR: it merges itself once required\n * checks pass, so `--direct-merge` needs no babysitting. Returns whether it was enabled; on failure\n * (the repo doesn't allow auto-merge, `gh` too old) it prints the manual command and returns false.\n */\nfunction enableAutoMerge(forkPath: string, branch: string): boolean {\n console.info(pc.dim('enabling auto-merge (squash) once checks pass...'));\n const merge = mergePrSquash(forkPath, branch, { auto: true, deleteBranch: true });\n if (merge.ok) return true;\n\n console.info(pc.yellow('could not enable auto-merge (is it enabled for the repo?). merge it manually:'));\n if (merge.output) console.info(pc.dim(indentLines(merge.output)));\n console.info(pc.dim(` gh pr merge ${branch} --squash --delete-branch`));\n return false;\n}\n\n/**\n * Push the finished sync branch to `origin`, open a PR into the trunk, and switch back to the\n * trunk. Runs automatically once a rerun completes the merge cleanly.\n *\n * Before pushing, any merge commits on the branch are flattened away (see `flattenSyncBranch`)\n * so the PR never lists the upstream branch's entire history.\n *\n * With `--direct-merge`, once the PR is open GitHub auto-merge is enabled (see `enableAutoMerge`)\n * so it squash-merges itself as soon as required checks pass — no forgotten open PR to trip over.\n *\n * Every step degrades gracefully: a failed push (no `origin`, auth) prints the manual steps and\n * leaves you on the branch; a missing/failed `gh` (or an existing PR) prints the `gh` command but\n * still returns you to the trunk since the branch is already pushed.\n */\nasync function shipSyncBranch(config: RuntimeConfig, branch: string): Promise<void> {\n const { forkPath, settings } = config;\n const base = resolveReleaseBase(settings);\n\n const flattened = await flattenSyncBranch(forkPath, branch, base);\n let prUrl: string | undefined;\n let prOpened = false;\n let autoMergeEnabled = false;\n\n // The squash commit's subject is the versioned sync message — reuse it as the PR title so the\n // PR name carries the upstream version and commit id (release-please only needs the prefix).\n const headSubject = (await getCommitInfo(forkPath, 'HEAD').catch(() => null))?.message;\n const prTitle = headSubject?.startsWith(SYNC_PR_TITLE) ? headSubject : SYNC_PR_TITLE;\n\n console.info(pc.dim(`pushing '${branch}' to origin...`));\n try {\n await pushBranch(forkPath, 'origin', branch, { forceWithLease: flattened });\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n console.info(pc.yellow(`push failed (${detail.split('\\n')[0]}). finish manually:`));\n printShipSteps(branch, base, prTitle);\n return;\n }\n\n if (ghAvailable()) {\n console.info(pc.dim('opening a pull request...'));\n const prBody = await buildSyncPrBodyForBranch(forkPath, base);\n const bodyArgs = prBody ? ['--body', prBody] : ['--fill'];\n const pr = spawnSync('gh', ['pr', 'create', '--base', base, '--head', branch, '--title', prTitle, ...bodyArgs], {\n cwd: forkPath,\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n prUrl = extractFirstUrl(`${pr.stdout ?? ''}\\n${pr.stderr ?? ''}`);\n prOpened = pr.status === 0;\n if (prOpened) {\n if (config.directMerge) autoMergeEnabled = enableAutoMerge(forkPath, branch);\n } else {\n console.info(pc.yellow('could not open the PR automatically (it may already exist). open it with:'));\n if (prUrl) console.info(pc.dim(` ${prUrl}`));\n printPrCreateStep(branch, base, prTitle);\n }\n } else {\n console.info(pc.yellow('`gh` not found — open the PR manually:'));\n printPrCreateStep(branch, base, prTitle);\n }\n\n console.info(pc.dim(`switching back to '${base}'...`));\n await switchBranch(forkPath, base);\n await pullFastForward(forkPath).catch(() => {});\n\n console.info();\n if (prUrl) {\n console.info(`${pc.green('✓')} Sync pull request ${prOpened ? 'opened' : 'ready'}`);\n const status = autoMergeEnabled\n ? `auto-merge on — squashes into '${base}' when checks pass`\n : `branch pushed, back on '${base}'`;\n console.info(pc.dim(` ${prUrl} · ${status}`));\n } else {\n console.info(`${pc.green('✓')} Sync branch pushed`);\n console.info(pc.dim(` '${branch}' is on origin, back on '${base}'`));\n }\n}\n\n/**\n * Reconcile dependencies and regenerate derived files before committing a resumed merge.\n *\n * A sync merge (plus package.json key-sync) changes `package.json`, which leaves the lockfile\n * and generated files (SDK, etc.) stale and often unstaged. Mirroring what lefthook would do —\n * but up front — we run `pnpm install` then `pnpm check`, so the merge commit is complete and\n * consistent. Returns false if a step fails (the merge is left in progress to retry).\n */\nfunction finalizeWorkspace(forkPath: string): boolean {\n for (const args of [['install'], ['check']]) {\n console.info(pc.dim(`running pnpm ${args.join(' ')}...`));\n const result = spawnSync('pnpm', args, { cwd: forkPath, stdio: 'inherit' });\n if (result.status !== 0) return false;\n }\n return true;\n}\n\n/** Outcome of a sync cycle run on a fresh temporary branch. */\ntype SyncCycleOutcome =\n | { status: 'conflicts'; branch: TemporarySyncBranch }\n | { status: 'staged'; branch: TemporarySyncBranch }\n | { status: 'noop' };\n\n/**\n * Run one sync cycle on a fresh temporary branch: cut the branch, merge upstream (+ packages),\n * and report the resulting state.\n *\n * - `conflicts`: merge staged with unresolved conflicts, left for IDE resolution.\n * - `staged`: clean merge staged, ready to commit.\n * - `noop`: upstream had nothing new; the throwaway branch was deleted and the original branch\n * restored.\n */\nasync function runSyncCycle(config: RuntimeConfig): Promise<SyncCycleOutcome> {\n const { forkPath } = config;\n const branch = await setupTemporarySyncBranch(config);\n\n const result = await runSync(config, { stagedBranch: branch.temporaryBranch });\n\n if (config.settings.syncWithPackages !== false) {\n // Run package sync even when the merge left conflicts: package.json files that are\n // themselves conflicted are skipped and reported; all others are still synced.\n await runPackages(config, { conflictedFiles: result.conflicts });\n }\n\n if (result.conflicts.length > 0) return { status: 'conflicts', branch };\n\n // Nothing staged: already up to date. Clean up the throwaway branch.\n if (!mergeInProgress(forkPath)) {\n await switchBranch(forkPath, branch.startBranch === branch.temporaryBranch ? branch.base : branch.startBranch);\n await deleteBranch(forkPath, branch.temporaryBranch);\n return { status: 'noop' };\n }\n\n return { status: 'staged', branch };\n}\n\n/**\n * Finish an in-progress merge left by an earlier `cella sync` run on the same temporary branch.\n *\n * This is what makes the command idempotent: after a run stops at conflicts, resolve and stage\n * them, then run `cella sync` again. If conflicts remain we point them out and stop; once none\n * remain we reconcile dependencies (`pnpm install` + `pnpm check`), stage everything, commit the\n * staged delta as a single squashed commit (see `commitSquash`), then push the branch and open\n * the PR (see `shipSyncBranch`).\n */\nasync function resumeSyncMerge(config: RuntimeConfig, branch: string): Promise<void> {\n const { forkPath } = config;\n const conflicts = await getConflictedFiles(forkPath);\n\n console.info();\n if (conflicts.length > 0) {\n console.info(pc.yellow(`${conflicts.length} file(s) still conflict on '${branch}':`));\n for (const file of conflicts) console.info(pc.dim(` ${file}`));\n console.info(pc.dim('resolve and stage them, then re-run `pnpm cella sync` to finish (it commits for you).'));\n return;\n }\n\n // Stage everything up front (resolved conflicts + any manual edits) before running tooling that\n // may fail: `finalizeWorkspace` returns early on a failing `pnpm check`, so staging afterwards\n // would never happen and the edits would never be recorded in the merge.\n await stageAll(forkPath);\n\n // Reconcile deps + regenerate derived files (package.json key-sync and the merge both touch\n // package.json, leaving the lockfile and generated files stale/unstaged).\n if (!finalizeWorkspace(forkPath)) {\n console.info();\n console.info(\n pc.yellow('`pnpm install`/`pnpm check` failed. fix the issues, then re-run `pnpm cella sync` to finish.'),\n );\n return;\n }\n\n // Build the commit subject before squashing (commitSquash clears MERGE_HEAD), re-stage (the\n // install/check step may have touched files), then commit the staged delta as a single-parent\n // commit so the PR shows one clean commit instead of the whole upstream history (the merge's\n // upstream ancestry isn't shared on the remote).\n const message = await buildSyncCommitMessage(forkPath, 'MERGE_HEAD');\n await stageAll(forkPath);\n await commitSquash(forkPath, message);\n console.info();\n console.info(pc.green(`committed the sync on '${branch}' as '${message}'.`));\n await shipSyncBranch(config, branch);\n}\n\n/**\n * Merge the open sync PR(s) so the trunk carries the recorded sync point before a new cycle cuts\n * from it. The newest PR is a content superset of any older ones (each cycle re-syncs from the\n * same stale trunk base), so the newest is squash-merged and the rest are closed.\n *\n * A merge GitHub refuses — conflicts with the trunk, or failing required checks (the \"breaking\n * changes\" to fix first) — stops the run: those must be resolved on the PR before syncing again.\n * On success the trunk is fast-forwarded locally so the fresh cycle cuts from it.\n */\nasync function mergeOpenSyncPrs(config: RuntimeConfig, open: GhPullRequest[]): Promise<'continue' | 'cancel'> {\n const { forkPath, settings } = config;\n const base = resolveReleaseBase(settings);\n const [newest, ...superseded] = open;\n\n console.info();\n console.info(pc.dim(`squash-merging #${newest.number} into '${base}'...`));\n const merged = mergePrSquash(forkPath, newest.number, { deleteBranch: true });\n if (!merged.ok) {\n console.info();\n console.info(pc.yellow(`could not merge #${newest.number} — resolve it first, then re-run \\`pnpm cella sync\\`:`));\n if (merged.output) console.info(pc.dim(indentLines(merged.output)));\n console.info(pc.dim(` ${newest.url}`));\n return 'cancel';\n }\n console.info(`${pc.green('✓')} merged #${newest.number}`);\n // Drop the stale local branch that tracked the merged PR (the remote one went with --delete-branch).\n await deleteBranch(forkPath, newest.headRefName);\n\n for (const pr of superseded) {\n console.info(pc.dim(`closing #${pr.number} — its changes are included in #${newest.number}...`));\n closePr(forkPath, pr.number);\n await deleteBranch(forkPath, pr.headRefName);\n }\n\n // Bring the merged commit into the local trunk so the new cycle cuts from an up-to-date base.\n console.info(pc.dim(`switching to '${base}' and fast-forwarding...`));\n await switchBranch(forkPath, base);\n await pullFastForward(forkPath);\n\n return 'continue';\n}\n\n/**\n * Before cutting a fresh sync branch, warn when an earlier sync PR is still open and unmerged.\n *\n * The last-sync point is recorded in the manifest committed *on the sync branch*, not on the\n * trunk. So a new cycle cut from a trunk that still lacks a merged sync PR re-includes that PR's\n * whole delta on top of the new upstream commits — the \"why are there suddenly so many changes\"\n * surprise. This offers to squash-merge the open PR first (so the new cycle cuts from an\n * up-to-date trunk), continue anyway, or cancel.\n *\n * Degrades to a silent no-op (`continue`) when it can't help: no `gh`, no open sync PR, or a\n * non-interactive session (no TTY to prompt on).\n */\nasync function guardAgainstOpenSyncPr(config: RuntimeConfig): Promise<'continue' | 'cancel'> {\n const { forkPath } = config;\n\n if (!ghAvailable() || !process.stdout.isTTY) return 'continue';\n\n const open = listOpenSyncPrs(forkPath, DEFAULT_SYNC_PREFIX);\n if (open.length === 0) return 'continue';\n\n const many = open.length > 1;\n console.info();\n console.info(\n `${warningMark} ${pc.yellow(`${many ? `${open.length} earlier sync PRs are` : 'an earlier sync PR is'} still open and unmerged:`)}`,\n );\n for (const pr of open) {\n console.info(pc.dim(` #${pr.number} ${pr.title}`));\n console.info(pc.dim(` ${pr.url}`));\n }\n console.info(pc.dim(` starting a new sync now produces a PR that re-includes ${many ? 'these' : 'those'} changes.`));\n console.info();\n\n const choice = await select<'merge' | 'continue' | 'cancel'>({\n message: 'how do you want to proceed?',\n choices: [\n {\n value: 'merge',\n name: `merge ${many ? 'them' : `#${open[0].number}`} first, then sync ${pc.dim('(recommended)')}`,\n },\n { value: 'continue', name: `continue anyway ${pc.dim('(new PR will re-include the unmerged changes)')}` },\n { value: 'cancel', name: pc.red('cancel') },\n ],\n loop: false,\n });\n\n if (choice === 'cancel') return 'cancel';\n if (choice === 'continue') return 'continue';\n return mergeOpenSyncPrs(config, open);\n}\n\n/**\n * Run the standalone `cella sync` command.\n *\n * Idempotent. Behaviour depends on where you are:\n * - On a sync branch with a merge in progress: finish that merge (resume after conflicts), then\n * push and open the PR.\n * - On a sync branch with the merge already committed: push and open the PR (e.g. a previous\n * push failed), then switch back to the trunk.\n * - Anywhere else: require a clean tree, then cut a fresh temporary branch and merge upstream.\n */\nexport async function runSyncCommand(config: RuntimeConfig): Promise<void> {\n const { forkPath } = config;\n const currentBranch = await getCurrentBranch(forkPath);\n const onSyncBranch = isTemporarySyncBranch(currentBranch);\n\n // Resume path: an earlier run left a merge staged on this temporary branch (e.g. after\n // conflicts). Re-running finishes it instead of starting over.\n if (onSyncBranch && mergeInProgress(forkPath)) {\n await resumeSyncMerge(config, currentBranch);\n return;\n }\n\n // On a sync branch with the merge already committed: ship it (push + PR + back to trunk).\n if (onSyncBranch) {\n // shipSyncBranch only pushes HEAD, so any edits made after the squash commit would be silently\n // left out of the pushed branch/PR. Refuse to ship over a dirty tree and make them commit.\n if (!(await isClean(forkPath))) {\n console.info();\n console.info(\n pc.yellow(\n `sync branch '${currentBranch}' has uncommitted changes.\\n` +\n 'commit them first (`git commit --amend --no-edit` or a new commit).',\n ),\n );\n return;\n }\n await shipSyncBranch(config, currentBranch);\n return;\n }\n\n // Fresh cycle: only ever cut the temporary branch from a clean tree.\n await assertClean(forkPath);\n\n // Guard against stacking: if an earlier sync PR is still open, its delta would re-appear in\n // this cycle's PR. Offer to merge it first (or bail) before cutting a new branch.\n if ((await guardAgainstOpenSyncPr(config)) === 'cancel') return;\n\n const outcome = await runSyncCycle(config);\n console.info();\n\n if (outcome.status === 'noop') {\n console.info(pc.green('already up to date with upstream — nothing to sync.'));\n return;\n }\n\n const { temporaryBranch } = outcome.branch;\n if (outcome.status === 'conflicts') {\n console.info(`${warningMark} ${pc.yellow(`conflicts on '${temporaryBranch}'. Resolve and stage them, then:`)}`);\n printFinishSteps();\n console.info(pc.dim(' rerun commits the sync, pushes the branch, and opens a PR.'));\n console.info(pc.dim(' let the rerun commit — a manual `git commit` records a merge commit that bloats the PR.'));\n }\n}\n","/**\n * GitHub CLI (`gh`) helpers for the cella CLI.\n *\n * Thin wrappers around `gh` used by the sync service to list, merge, and close the sync pull\n * requests. Every wrapper degrades gracefully when `gh` is missing or a call fails, so a sync\n * run on a repo without `gh`/`origin` still works — it just skips the PR automation.\n */\n\nimport { spawnSync } from 'node:child_process';\n\n/** An open pull request, as returned by `gh pr list --json`. */\nexport interface GhPullRequest {\n number: number;\n title: string;\n headRefName: string;\n url: string;\n}\n\n/** Result of a `gh` invocation: whether it exited 0, plus its combined stdout+stderr. */\nexport interface GhResult {\n ok: boolean;\n output: string;\n}\n\n/** Whether the GitHub CLI is available on PATH. */\nexport function ghAvailable(): boolean {\n return spawnSync('gh', ['--version'], { stdio: 'ignore' }).status === 0;\n}\n\n/** Run `gh` in `cwd`, capturing stdout+stderr. Never throws. */\nfunction runGh(cwd: string, args: string[]): GhResult {\n const result = spawnSync('gh', args, { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });\n const output = `${result.stdout ?? ''}${result.stderr ?? ''}`.trim();\n return { ok: result.status === 0, output };\n}\n\n/**\n * Keep only the pull requests whose head branch is one of cella's temporary sync branches\n * (under the `<prefix>/` namespace, e.g. `cella/sync/`). Pure — unit-tested.\n */\nexport function filterSyncPrs(prs: GhPullRequest[], prefix: string): GhPullRequest[] {\n return prs.filter((pr) => pr.headRefName.startsWith(`${prefix}/`));\n}\n\n/**\n * List open sync PRs (head branch under `<prefix>/`), newest first (highest PR number).\n * Returns an empty array when `gh` fails (no auth, no origin) so callers degrade to a no-op.\n */\nexport function listOpenSyncPrs(cwd: string, prefix: string): GhPullRequest[] {\n const { ok, output } = runGh(cwd, [\n 'pr',\n 'list',\n '--state',\n 'open',\n '--json',\n 'number,title,headRefName,url',\n '--limit',\n '50',\n ]);\n if (!ok || !output) return [];\n\n let parsed: GhPullRequest[];\n try {\n parsed = JSON.parse(output) as GhPullRequest[];\n } catch {\n return [];\n }\n\n return filterSyncPrs(parsed, prefix).sort((a, b) => b.number - a.number);\n}\n\n/**\n * Build the argv for `gh pr merge`. Pure — unit-tested.\n *\n * `auto` uses GitHub auto-merge (the PR squashes once required checks pass); without it the\n * merge is attempted immediately and fails when the PR is not mergeable.\n */\nexport function buildMergeArgs(ref: string, options: { auto?: boolean; deleteBranch?: boolean } = {}): string[] {\n const args = ['pr', 'merge', ref, '--squash'];\n if (options.auto) args.push('--auto');\n if (options.deleteBranch) args.push('--delete-branch');\n return args;\n}\n\n/** Squash-merge a PR (by number, branch, or URL). See {@link buildMergeArgs}. */\nexport function mergePrSquash(\n cwd: string,\n ref: string | number,\n options: { auto?: boolean; deleteBranch?: boolean } = {},\n): GhResult {\n return runGh(cwd, buildMergeArgs(String(ref), options));\n}\n\n/** Close a PR without merging (used to discard superseded sync PRs). */\nexport function closePr(cwd: string, ref: string | number): GhResult {\n return runGh(cwd, ['pr', 'close', String(ref)]);\n}\n","/**\n * Packages service for sync CLI v2.\n *\n * Syncs package.json keys between fork and upstream using safe merge logic:\n * - Add-only: new entries from upstream are added\n * - Bump-only: versions are only upgraded, never downgraded\n * - Never remove: fork entries not in upstream are preserved\n * - Supports nested `pnpm` key (overrides, patchedDependencies, packageExtensions)\n */\n\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { PackageJsonSyncKey, RuntimeConfig } from '../config/types';\nimport pc from '../utils/colors';\nimport { createSpinner, spinnerSuccess, spinnerText, warningMark } from '../utils/display';\nimport { git } from '../utils/git';\n\n/** Package.json structure */\ninterface PackageJson {\n name?: string;\n version?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n engines?: Record<string, string>;\n packageManager?: string;\n overrides?: Record<string, string>;\n pnpm?: {\n overrides?: Record<string, string>;\n patchedDependencies?: Record<string, string>;\n packageExtensions?: Record<string, Record<string, unknown>>;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\ninterface ComparableVersion {\n major: number;\n minor: number;\n patch: number;\n}\n\nfunction parseComparableVersion(version: string): ComparableVersion | null {\n const trimmed = version.trim();\n\n if (\n trimmed === '' ||\n trimmed === '*' ||\n trimmed.includes('workspace:') ||\n trimmed.includes('catalog:') ||\n trimmed.includes('file:') ||\n trimmed.includes('link:') ||\n trimmed.includes('git+') ||\n trimmed.includes('github:') ||\n trimmed.includes('http://') ||\n trimmed.includes('https://') ||\n trimmed.includes('||')\n ) {\n return null;\n }\n\n const match = trimmed.match(\n /^(?:\\^|~|>=|<=|>|<|=)?\\s*v?(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/,\n );\n\n if (!match) return null;\n\n return {\n major: Number(match[1]),\n minor: Number(match[2] ?? 0),\n patch: Number(match[3] ?? 0),\n };\n}\n\nfunction compareVersions(left: ComparableVersion, right: ComparableVersion): number {\n if (left.major !== right.major) return left.major - right.major;\n if (left.minor !== right.minor) return left.minor - right.minor;\n return left.patch - right.patch;\n}\n\n/**\n * Check if upstream version is higher than fork version.\n * Returns true only if upstream is strictly higher — never downgrades.\n * For non-parseable values (workspace:*, etc.), returns false (keep fork's).\n */\nfunction isHigherVersion(upstreamVersion: string, forkVersion: string): boolean {\n if (upstreamVersion === forkVersion) return false;\n\n const upCoerced = parseComparableVersion(upstreamVersion);\n const forkCoerced = parseComparableVersion(forkVersion);\n\n if (!upCoerced || !forkCoerced) return false;\n\n return compareVersions(upCoerced, forkCoerced) > 0;\n}\n\n/**\n * Safe merge for Record<string, string> — add new entries, bump versions, never remove or downgrade.\n * With `addOnly` (e.g. scripts), existing fork entries are never overwritten.\n * Returns the merged record sorted alphabetically, plus the keys that were newly added.\n */\nfunction safeMergeRecord(\n forkRecord: Record<string, string> | undefined,\n upstreamRecord: Record<string, string> | undefined,\n addOnly = false,\n): { merged: Record<string, string>; changed: boolean; added: string[] } | undefined {\n if (!upstreamRecord) return undefined;\n\n const merged = { ...(forkRecord || {}) };\n const added: string[] = [];\n let changed = false;\n\n for (const [name, upstreamValue] of Object.entries(upstreamRecord)) {\n const forkValue = merged[name];\n\n if (forkValue === undefined) {\n // New entry from upstream — add it\n merged[name] = upstreamValue;\n added.push(name);\n changed = true;\n } else if (!addOnly && forkValue !== upstreamValue && isHigherVersion(upstreamValue, forkValue)) {\n // Upstream has a higher version — bump (preserve upstream's range prefix)\n merged[name] = upstreamValue;\n changed = true;\n }\n // Otherwise: fork has equal or higher version, or non-parseable — keep fork's\n }\n\n // Sort alphabetically\n const sorted = Object.fromEntries(Object.entries(merged).sort(([a], [b]) => a.localeCompare(b)));\n return { merged: sorted, changed, added };\n}\n\n/**\n * Safe merge for the `pnpm` key — recurse into sub-objects with add/bump-only logic.\n */\nfunction safeMergePnpm(\n forkPnpm: PackageJson['pnpm'],\n upstreamPnpm: PackageJson['pnpm'],\n): { merged: PackageJson['pnpm']; changed: boolean } | undefined {\n if (!upstreamPnpm) return undefined;\n\n const merged: NonNullable<PackageJson['pnpm']> = { ...(forkPnpm || {}) };\n let changed = false;\n\n // pnpm.overrides — same as dependency overrides: add new, bump versions\n if (upstreamPnpm.overrides) {\n const result = safeMergeRecord(\n merged.overrides as Record<string, string> | undefined,\n upstreamPnpm.overrides as Record<string, string>,\n );\n if (result?.changed) {\n merged.overrides = result.merged;\n changed = true;\n }\n }\n\n // pnpm.patchedDependencies — add-only (version comparison doesn't apply to patch paths)\n if (upstreamPnpm.patchedDependencies) {\n const forkPatched = (merged.patchedDependencies || {}) as Record<string, string>;\n const upstreamPatched = upstreamPnpm.patchedDependencies as Record<string, string>;\n\n for (const [name, value] of Object.entries(upstreamPatched)) {\n if (!(name in forkPatched)) {\n forkPatched[name] = value;\n changed = true;\n }\n }\n\n if (changed || !merged.patchedDependencies) {\n merged.patchedDependencies = Object.fromEntries(\n Object.entries(forkPatched).sort(([a], [b]) => a.localeCompare(b)),\n );\n }\n }\n\n // pnpm.packageExtensions — add new packages and add new sub-keys, never remove\n if (upstreamPnpm.packageExtensions) {\n const forkExts = (merged.packageExtensions || {}) as Record<string, Record<string, unknown>>;\n const upstreamExts = upstreamPnpm.packageExtensions as Record<string, Record<string, unknown>>;\n\n for (const [pkg, upstreamExt] of Object.entries(upstreamExts)) {\n if (!(pkg in forkExts)) {\n // New package extension — add entirely\n forkExts[pkg] = upstreamExt;\n changed = true;\n } else {\n // Existing package — add new sub-keys only\n for (const [subKey, subValue] of Object.entries(upstreamExt)) {\n if (!(subKey in forkExts[pkg])) {\n forkExts[pkg][subKey] = subValue;\n changed = true;\n }\n }\n }\n }\n\n merged.packageExtensions = forkExts;\n }\n\n // Other pnpm sub-keys — add if missing in fork\n for (const [key, value] of Object.entries(upstreamPnpm)) {\n if (['overrides', 'patchedDependencies', 'packageExtensions'].includes(key)) continue;\n if (!(key in merged)) {\n merged[key] = value;\n changed = true;\n }\n }\n\n return { merged, changed };\n}\n\n/**\n * Read a package.json file.\n */\nfunction readPackageJson(filePath: string): PackageJson | null {\n if (!existsSync(filePath)) return null;\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Write a package.json file (pretty-printed).\n */\nfunction writePackageJson(filePath: string, data: PackageJson): void {\n writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\\n`, 'utf-8');\n}\n\n/**\n * Get package.json from upstream ref.\n */\nasync function getUpstreamPackageJson(\n forkPath: string,\n upstreamRef: string,\n relativePath: string,\n): Promise<PackageJson | null> {\n const filePath = relativePath ? `${relativePath}/package.json` : 'package.json';\n\n try {\n return JSON.parse(await git(['show', `${upstreamRef}:${filePath}`], forkPath));\n } catch {\n return null;\n }\n}\n\n/**\n * Discover all package.json locations that exist in both fork and upstream.\n */\nasync function discoverPackageLocations(forkPath: string, upstreamRef: string): Promise<string[]> {\n // Get all package.json paths from upstream\n const stdout = await git(['ls-tree', '-r', '--name-only', upstreamRef], forkPath, { ignoreErrors: true });\n const upstreamPaths = stdout\n .split('\\n')\n .filter((p) => p.endsWith('/package.json') || p === 'package.json')\n .map((p) => (p === 'package.json' ? '' : p.replace('/package.json', '')));\n\n // Filter to locations that also exist in fork\n return upstreamPaths.filter((loc) => existsSync(join(forkPath, loc, 'package.json')));\n}\n\n/**\n * Sync a single package.json file with safe merge logic.\n */\nasync function syncPackageJson(\n forkPath: string,\n upstreamRef: string,\n relativePath: string,\n keysToSync: PackageJsonSyncKey[],\n): Promise<{ updated: boolean; changes: string[] }> {\n const changes: string[] = [];\n const pkgPath = join(forkPath, relativePath, 'package.json');\n\n const forkPkg = readPackageJson(pkgPath);\n const upstreamPkg = await getUpstreamPackageJson(forkPath, upstreamRef, relativePath);\n\n if (!forkPkg || !upstreamPkg) {\n return { updated: false, changes };\n }\n\n let updated = false;\n\n for (const key of keysToSync) {\n if (key === 'pnpm') {\n // Handle nested pnpm key\n const result = safeMergePnpm(forkPkg.pnpm, upstreamPkg.pnpm);\n if (result?.changed) {\n forkPkg.pnpm = result.merged;\n updated = true;\n changes.push('pnpm: merged');\n }\n continue;\n }\n\n if (key === 'packageManager') {\n // String key — only bump, never downgrade\n const upstreamValue = upstreamPkg[key] as string | undefined;\n const forkValue = forkPkg[key] as string | undefined;\n\n if (upstreamValue && !forkValue) {\n forkPkg[key] = upstreamValue;\n updated = true;\n changes.push(`${key}: added`);\n } else if (\n upstreamValue &&\n forkValue &&\n upstreamValue !== forkValue &&\n isHigherVersion(upstreamValue, forkValue)\n ) {\n forkPkg[key] = upstreamValue;\n updated = true;\n changes.push(`${key}: bumped`);\n }\n continue;\n }\n\n // All Record<string, string> keys — safe merge.\n // Scripts are add-only (never overwrite fork scripts); the rest also bump versions.\n const forkValue = forkPkg[key] as Record<string, string> | undefined;\n const upstreamValue = upstreamPkg[key] as Record<string, string> | undefined;\n\n const addOnly = key === 'scripts';\n const result = safeMergeRecord(forkValue, upstreamValue, addOnly);\n if (result?.changed) {\n (forkPkg as Record<string, unknown>)[key] = result.merged;\n updated = true;\n if (addOnly) {\n changes.push(...result.added.map((name) => `scripts.${name}: added`));\n } else {\n changes.push(`${key}: merged`);\n }\n }\n }\n\n if (updated) {\n writePackageJson(pkgPath, forkPkg);\n }\n\n return { updated, changes };\n}\n\n/**\n * Run the packages sync service.\n *\n * Dynamically discovers all package.json locations in both fork and upstream,\n * then syncs configured keys using safe merge logic (add-only, bump-only).\n *\n * When `conflictedFiles` is provided (e.g. after a sync that left conflicts),\n * any package.json that is itself unmerged is skipped to avoid clobbering\n * conflict markers; all other package.json files are still synced.\n */\nexport async function runPackages(config: RuntimeConfig, options: { conflictedFiles?: string[] } = {}): Promise<void> {\n createSpinner('syncing package.json files...');\n\n const keysToSync = config.settings.packageJsonSync || ['dependencies', 'devDependencies'];\n const conflictedSet = new Set(options.conflictedFiles ?? []);\n\n // Dynamically discover package locations\n const locations = await discoverPackageLocations(config.forkPath, config.upstreamRef);\n let changedCount = 0;\n const skipped: string[] = [];\n\n for (const location of locations) {\n const pkgRelPath = location ? `${location}/package.json` : 'package.json';\n\n // Skip package.json files that are themselves conflicted from the merge —\n // writing to them would clobber the conflict markers the user must resolve.\n if (conflictedSet.has(pkgRelPath)) {\n skipped.push(pkgRelPath);\n continue;\n }\n\n spinnerText(`syncing ${location || 'root'}/package.json...`);\n\n const { updated } = await syncPackageJson(config.forkPath, config.upstreamRef, location, keysToSync);\n\n if (updated) {\n changedCount += 1;\n }\n }\n\n spinnerSuccess(\n 'package sync complete',\n `${changedCount} package.json${changedCount === 1 ? ' was' : 's were'} changed`,\n );\n\n // Report any package.json files deferred due to merge conflicts\n if (skipped.length > 0) {\n console.info();\n console.warn(\n `${warningMark} skipped ${skipped.length} conflicted package.json file(s) — resolve the conflicts, commit the merge, then rerun \\`pnpm cella sync\\`:`,\n );\n for (const path of skipped) {\n console.warn(` ${pc.dim('→')} ${path}`);\n }\n }\n}\n","/**\n * Stats service for cella CLI.\n *\n * Counts files in the codebase using `git ls-files` (fast, respects .gitignore).\n * Categorizes by type and workspace package.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport pc from '../utils/colors';\nimport { printCoverageSummary } from '../utils/coverage-utils';\nimport { createSpinner, DIVIDER, spinnerSuccess } from '../utils/display';\nimport { git } from '../utils/git';\nimport { parseYamlBlockList } from '../utils/yaml';\n\n/** Extensions Biome can check (source code, config, styles) */\nconst sourceExtensions = new Set(['ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'json', 'jsonc', 'css', 'html']);\n\n/** File category for classification */\ntype FileCategory = 'test' | 'stories' | 'generated' | 'json' | 'other';\n\n/** Stats result for display or JSON output */\ninterface StatsResult {\n total: number;\n totalLoc: number;\n skipped: number;\n categories: Record<FileCategory, { files: number; loc: number }>;\n packages: Record<\n string,\n { total: number; loc: number; categories: Record<FileCategory, { files: number; loc: number }> }\n >;\n}\n\n/** Workspace package definition from pnpm-workspace.yaml */\ninterface WorkspacePackage {\n /** Display name (e.g., 'backend', 'cli/cella') */\n name: string;\n /** Path prefix to match (e.g., 'backend/', 'cli/cella/') */\n prefix: string;\n}\n\n/**\n * Parse pnpm-workspace.yaml to extract package paths.\n */\nasync function getWorkspacePackages(forkPath: string): Promise<WorkspacePackage[]> {\n const content = await readFile(join(forkPath, 'pnpm-workspace.yaml'), 'utf-8');\n\n return parseYamlBlockList(content, 'packages').map((pattern) => {\n // Handle wildcard patterns like 'cli/*' — resolved per file when matching\n if (pattern.endsWith('/*')) {\n const base = pattern.slice(0, -2);\n return { name: `${base}/*`, prefix: `${base}/` };\n }\n return { name: pattern, prefix: `${pattern}/` };\n });\n}\n\n/**\n * Classify a file path into a category.\n */\nfunction classifyFile(filePath: string): FileCategory {\n // Test files\n if (\n filePath.includes('.test.') ||\n filePath.includes('.spec.') ||\n filePath.includes('/tests/') ||\n filePath.includes('/test/') ||\n filePath.startsWith('tests/') ||\n filePath.includes('/__tests__/')\n ) {\n return 'test';\n }\n\n // Storybook stories\n if (filePath.includes('.stories.')) {\n return 'stories';\n }\n\n // Generated files\n if (\n filePath.includes('.gen.') ||\n filePath.includes('.gen/') ||\n filePath.includes('/gen/') ||\n filePath.startsWith('drizzle/') ||\n filePath.includes('/drizzle/') ||\n filePath.endsWith('.d.ts') ||\n filePath.includes('.tsbuildinfo')\n ) {\n return 'generated';\n }\n\n // JSON\n if (filePath.endsWith('.json') || filePath.endsWith('.jsonc')) {\n return 'json';\n }\n\n return 'other';\n}\n\n/**\n * Match a file to its workspace package, handling wildcard patterns.\n */\nfunction matchPackage(filePath: string, packages: WorkspacePackage[]): string {\n for (const pkg of packages) {\n if (pkg.name.endsWith('/*')) {\n // Wildcard: match any subfolder under the base prefix\n if (filePath.startsWith(pkg.prefix)) {\n // Extract the actual subpackage name (e.g., 'cli/cella' from 'cli/cella/src/foo.ts')\n const rest = filePath.slice(pkg.prefix.length);\n const subDir = rest.split('/')[0];\n if (subDir) {\n return `${pkg.prefix}${subDir}`;\n }\n }\n } else if (filePath.startsWith(pkg.prefix)) {\n return pkg.name;\n }\n }\n return '(root)';\n}\n\n/** Pathspec patterns for source extensions */\nconst sourcePathspecs = [...sourceExtensions].map((ext) => `*.${ext}`);\n\n/**\n * Collect file stats from the repository.\n * Uses `git grep -c ''` to get file list + line counts in a single call.\n */\nasync function collectStats(forkPath: string): Promise<StatsResult> {\n // Get all tracked source files with line counts (respects .gitignore, ~15ms)\n const output = await git(['grep', '-c', '', '--', ...sourcePathspecs], forkPath, { ignoreErrors: true });\n const allFilesOutput = await git(['ls-files', '--cached'], forkPath);\n const allFilesCount = allFilesOutput.split('\\n').filter(Boolean).length;\n\n const packages = await getWorkspacePackages(forkPath);\n\n // Parse \"path:count\" lines\n const entries: { path: string; loc: number }[] = [];\n for (const line of output.split('\\n')) {\n if (!line) continue;\n const sep = line.lastIndexOf(':');\n if (sep === -1) continue;\n entries.push({ path: line.slice(0, sep), loc: Number.parseInt(line.slice(sep + 1), 10) });\n }\n\n const skipped = allFilesCount - entries.length;\n const emptyCat = () => ({\n test: { files: 0, loc: 0 },\n stories: { files: 0, loc: 0 },\n generated: { files: 0, loc: 0 },\n json: { files: 0, loc: 0 },\n other: { files: 0, loc: 0 },\n });\n const categories = emptyCat();\n const pkgStats = new Map<\n string,\n { total: number; loc: number; categories: Record<FileCategory, { files: number; loc: number }> }\n >();\n let totalLoc = 0;\n\n for (const { path, loc } of entries) {\n const category = classifyFile(path);\n categories[category].files++;\n categories[category].loc += loc;\n totalLoc += loc;\n\n const pkg = matchPackage(path, packages);\n let entry = pkgStats.get(pkg);\n if (!entry) {\n entry = { total: 0, loc: 0, categories: emptyCat() };\n pkgStats.set(pkg, entry);\n }\n entry.total++;\n entry.loc += loc;\n entry.categories[category].files++;\n entry.categories[category].loc += loc;\n }\n\n // Sort packages by source LOC descending\n const sortedPackages = Object.fromEntries(\n [...pkgStats.entries()].sort((a, b) => b[1].categories.other.loc - a[1].categories.other.loc),\n );\n\n return { total: entries.length, totalLoc, skipped, categories, packages: sortedPackages };\n}\n\n/**\n * Format a number with padding for table alignment.\n */\nfunction pad(n: number, width = 6): string {\n return String(n).padStart(width);\n}\n\n/**\n * Format a number with K suffix for large values.\n */\nfunction formatLoc(n: number): string {\n if (n >= 1000) return `${(n / 1000).toFixed(1)}k`;\n return String(n);\n}\n\n/**\n * Format a LOC value for fixed-width table columns.\n */\nfunction formatLocColumn(n: number, width = 8): string {\n return formatLoc(n).padStart(width);\n}\n\n/**\n * Format a percentage with fixed width (e.g., '05.0%', '89.7%').\n */\nfunction fmtPct(value: number, total: number): string {\n const pct = ((value / total) * 100).toFixed(1);\n return `${pct.padStart(5)}%`;\n}\n\n/**\n * Print stats in table format.\n */\nfunction printStats(stats: StatsResult, verbose: boolean): void {\n console.info();\n console.info(\n ` ${pc.bold('source files')} ${String(stats.total)} ${pc.dim(`(${stats.skipped} non-source skipped)`)}`,\n );\n console.info(` ${pc.bold('lines of code')} ${pc.cyan(formatLoc(stats.totalLoc))}`);\n console.info();\n\n const catEntries: [string, { files: number; loc: number }][] = [\n ['source & config', stats.categories.other],\n ['test', stats.categories.test],\n ['stories', stats.categories.stories],\n ['generated', stats.categories.generated],\n ['json', stats.categories.json],\n ];\n for (const [label, data] of catEntries) {\n console.info(\n ` ${pad(data.files)} ${pc.dim(fmtPct(data.files, stats.total))} ${label.padEnd(18)} ${pc.cyan(formatLocColumn(data.loc))} ${pc.dim(fmtPct(data.loc, stats.totalLoc))}`,\n );\n }\n\n console.info();\n console.info(DIVIDER);\n console.info();\n\n if (verbose) {\n // Verbose: show per-package category breakdown\n const header = ` ${''.padEnd(6)} ${'package'.padEnd(18)} ${'loc'.padStart(8)} ${'test'.padStart(6)} ${'story'.padStart(6)} ${'gen'.padStart(6)} ${'json'.padStart(6)} ${'src'.padStart(6)}`;\n console.info(pc.dim(header));\n for (const [name, data] of Object.entries(stats.packages)) {\n const c = data.categories;\n const srcFiles = c.other.files;\n const srcLoc = c.other.loc;\n if (srcFiles === 0) continue;\n console.info(\n ` ${pc.dim(pad(srcFiles))} ${name.padEnd(18)} ${pc.cyan(formatLocColumn(srcLoc))} ${pc.dim(pad(c.test.files))} ${pc.dim(pad(c.stories.files))} ${pc.dim(pad(c.generated.files))} ${pc.dim(pad(c.json.files))} ${pc.dim(pad(srcFiles))}`,\n );\n }\n } else {\n for (const [name, data] of Object.entries(stats.packages)) {\n const srcFiles = data.categories.other.files;\n const srcLoc = data.categories.other.loc;\n if (srcFiles === 0) continue;\n console.info(\n ` ${pad(srcFiles)} ${pc.dim(fmtPct(srcFiles, stats.categories.other.files))} ${name.padEnd(18)} ${pc.cyan(formatLocColumn(srcLoc))} ${pc.dim(fmtPct(srcLoc, stats.categories.other.loc))}`,\n );\n }\n }\n\n console.info();\n}\n\n/**\n * Run the stats service.\n */\nexport async function runStats(\n forkPath: string,\n options: { json?: boolean; verbose?: boolean; refreshCoverage?: boolean } = {},\n): Promise<void> {\n createSpinner('counting files...');\n const stats = await collectStats(forkPath);\n spinnerSuccess('Finished counting by raw line of code');\n\n if (options.json) {\n console.info(JSON.stringify(stats, null, 2));\n } else {\n printStats(stats, options.verbose ?? false);\n console.info();\n printCoverageSummary(forkPath, { refresh: options.refreshCoverage });\n }\n}\n","/**\n * Coverage utilities for the Cella CLI stats service.\n *\n * Reads the cached `.coverage/coverage-summary.json` produced by the\n * `json-summary` Vitest reporter (see root vitest.config.ts) and renders a\n * compact overview. The stats service normally only reads\n * the artifact from the last default `pnpm test` run, warning when it is stale\n * or missing. Passing `--coverage` refreshes it first.\n */\n\nimport { spawnSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport pc from './colors';\n\n/** A single metric block from a coverage-summary.json entry. */\ninterface CoverageMetric {\n total: number;\n covered: number;\n skipped: number;\n pct: number;\n}\n\n/** One file (or the `total`) entry in coverage-summary.json. */\ninterface CoverageEntry {\n lines: CoverageMetric;\n statements: CoverageMetric;\n functions: CoverageMetric;\n branches: CoverageMetric;\n}\n\n/** Shape of Vitest's coverage-summary.json. Keys are absolute file paths plus `total`. */\ntype CoverageSummary = Record<string, CoverageEntry> & { total: CoverageEntry };\n\n/** Coverage data is considered stale after this many ms (7 days). */\nconst STALE_THRESHOLD_MS = 7 * 24 * 60 * 60 * 1000;\n\n/** Path to the cached summary written by the `json-summary` reporter. */\nfunction summaryPath(forkPath: string): string {\n return path.join(forkPath, '.coverage', 'coverage-summary.json');\n}\n\n/** Color a percentage: green ≥ 80, yellow ≥ 50, red below. */\nfunction colorPct(pct: number): string {\n const label = `${pct.toFixed(2)}%`;\n if (pct >= 80) return pc.green(label);\n if (pct >= 50) return pc.yellow(label);\n return pc.red(label);\n}\n\n/** Human-friendly \"x days/hours ago\" from a timestamp. */\nfunction formatAge(ms: number): string {\n const days = Math.floor(ms / (24 * 60 * 60 * 1000));\n if (days >= 1) return `${days} day${days === 1 ? '' : 's'} ago`;\n const hours = Math.floor(ms / (60 * 60 * 1000));\n if (hours >= 1) return `${hours} hour${hours === 1 ? '' : 's'} ago`;\n const mins = Math.floor(ms / (60 * 1000));\n return `${mins} minute${mins === 1 ? '' : 's'} ago`;\n}\n\n/**\n * Re-run the full coverage suite via `pnpm test`. Output is streamed so the\n * user sees progress (Docker boot, test run, etc.). Returns true on success.\n */\nexport function refreshCoverage(forkPath: string): boolean {\n console.info(pc.dim('running `pnpm test` (this spins up Docker and runs the full suite)...'));\n const result = spawnSync('pnpm', ['test'], { cwd: forkPath, stdio: 'inherit' });\n return result.status === 0;\n}\n\n/**\n * Print a compact coverage overview from the cached summary file.\n *\n * @param forkPath - Repository root.\n * @param options.refresh - When true, run `pnpm test` first to regenerate\n * the cache before rendering.\n */\nexport function printCoverageSummary(forkPath: string, options: { refresh?: boolean } = {}): void {\n const file = summaryPath(forkPath);\n\n if (options.refresh) {\n const ok = refreshCoverage(forkPath);\n if (!ok) {\n console.info(pc.red('coverage run failed — showing last cached results (if any)'));\n }\n console.info();\n }\n\n if (!fs.existsSync(file)) {\n console.info(pc.bold('coverage'));\n console.info(pc.yellow(' no coverage data found — run `pnpm test` to generate it'));\n console.info();\n return;\n }\n\n let summary: CoverageSummary;\n let mtimeMs: number;\n try {\n summary = JSON.parse(fs.readFileSync(file, 'utf-8')) as CoverageSummary;\n mtimeMs = fs.statSync(file).mtimeMs;\n } catch {\n console.info(pc.bold('coverage'));\n console.info(pc.yellow(' could not read coverage-summary.json — run `pnpm test` to regenerate'));\n console.info();\n return;\n }\n\n const ageMs = Date.now() - mtimeMs;\n const stale = ageMs > STALE_THRESHOLD_MS;\n\n // Roll up per-package line coverage by the first path segment relative to root.\n const perPackage = new Map<string, { covered: number; total: number }>();\n for (const [key, entry] of Object.entries(summary)) {\n if (key === 'total') continue;\n const rel = path.relative(forkPath, key);\n if (rel.startsWith('..')) continue;\n const pkg = rel.split(path.sep)[0];\n const acc = perPackage.get(pkg) ?? { covered: 0, total: 0 };\n acc.covered += entry.lines.covered;\n acc.total += entry.lines.total;\n perPackage.set(pkg, acc);\n }\n\n // Header with freshness indicator.\n const ageLabel = formatAge(ageMs);\n console.info(pc.bold('coverage'), pc.dim(`(updated ${ageLabel})`));\n if (stale) {\n console.info(pc.yellow(' ⚠ data is older than 7 days — run `pnpm test` to refresh'));\n }\n\n // Overall totals.\n const total = summary.total;\n console.info(\n ` ${pc.bold('overall')} ` +\n `lines ${colorPct(total.lines.pct)} ${pc.dim(`(${total.lines.covered}/${total.lines.total})`)} ` +\n `funcs ${colorPct(total.functions.pct)} ` +\n `branches ${colorPct(total.branches.pct)}`,\n );\n\n // Per-package line coverage, worst first.\n const rows = [...perPackage.entries()]\n .map(([pkg, v]) => ({ pkg, pct: v.total ? (100 * v.covered) / v.total : 0, ...v }))\n .sort((a, b) => a.pct - b.pct);\n\n const nameWidth = Math.max(...rows.map((r) => r.pkg.length), 0);\n for (const r of rows) {\n console.info(` ${r.pkg.padEnd(nameWidth)} ${colorPct(r.pct)} ${pc.dim(`(${r.covered}/${r.total})`)}`);\n }\n console.info();\n}\n"],"mappings":"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","names":["existsSync","statSync","join","resolve","process","join","process","process","process","process","existsSync","join","z","pad","join","existsSync","z","join","resolve","process","process","resolve","join","existsSync","join","existsSync","join","join","process","basename","writeFileSync","basename","join","process","existsSync","tmpdir","basename","join","process","existsSync","mkdir","dirname","join","join","path","join","existsSync","fetch","dirname","join","mkdir","existsSync","path","join","tmpdir","basename","existsSync","process","path","fetch","basename","fs","path","execFile","promisify","execFileAsync","promisify","execFile","readFileSync","join","select","dirname","join","resolve","path","dirname","resolve","join","unlinkSync","existsSync","dirname","resolve","dirname","resolve","existsSync","readFileSync","join","checkbox","path","fork","select","resolve","process","Separator","select","spawnSync","select","spawnSync","existsSync","readFileSync","writeFileSync","join","existsSync","readFileSync","writeFileSync","join","result","upstreamValue","forkValue","path","merge","spawnSync","select","resolve","Separator","select","process","readFile","join","spawnSync","fs","path","spawnSync","readFile","join","sep","path","resolve","existsSync","statSync","process","join"]}