forgemap 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/forgemap.mjs +18 -10
- package/dist/bin/forgemap.mjs.map +1 -1
- package/package.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forgemap.mjs","names":[],"sources":["../../src/commands/cd.ts","../../src/utils/path.ts","../../src/config/load.ts","../../src/repos/scan.ts","../../src/repos/cache.ts","../../src/utils/exec.ts","../../src/forges/git.ts","../../src/utils/concurrency.ts","../../src/forges/github.ts","../../src/forges/registry.ts","../../src/slug/parse.ts","../../src/repos/git.ts","../../src/repos/evaluate.ts","../../src/commands/cleanup.ts","../../src/slug/resolve.ts","../../src/commands/clone.ts","../../src/utils/shell.ts","../../src/config/write.ts","../../src/commands/config/init.ts","../../src/commands/config/show.ts","../../src/commands/config/index.ts","../../src/commands/delete.ts","../../src/config/forges.ts","../../src/config/mutate.ts","../../src/repos/picker.ts","../../src/commands/forge/shared.ts","../../src/commands/forge/add.ts","../../src/commands/forge/edit.ts","../../src/commands/forge/remove.ts","../../src/commands/forge/index.ts","../../src/repos/import.ts","../../src/commands/import.ts","../../src/commands/info.ts","../../src/repos/filter.ts","../../src/repos/match.ts","../../src/commands/list.ts","../../src/slug/locate.ts","../../src/commands/open.ts","../../src/commands/path.ts","../../src/commands/pick.ts","../../src/commands/shell-init.ts","../../src/commands/status.ts","../../src/commands/sync.ts","../../src/commands/validate.ts","../../src/commands/completion.ts","../../src/cli.ts","../../src/bin/forgemap.ts"],"sourcesContent":["import { defineCommand } from 'citty';\nimport consola from 'consola';\n\n/**\n * When the shell wrapper from `forgemap shell-init` is sourced, it\n * intercepts `forgemap cd <slug>` before the binary is called and runs\n * the actual `cd` in the user's shell. If the binary itself ever runs\n * this command, the wrapper isn't active — we print a hint so the user\n * knows how to enable it.\n */\nexport const cdCommand = defineCommand({\n meta: {\n name: 'cd',\n description: 'Change directory into a repo (requires shell integration)'\n },\n args: {\n slug: {\n type: 'positional',\n description: 'owner/repo, forge:owner/repo, full URL, or fuzzy query',\n required: false\n }\n },\n async run() {\n consola.error(\n 'forgemap cd needs shell integration to actually change directory.'\n );\n consola.info('Source the wrapper once and try again:');\n consola.info(' eval \"$(forgemap shell-init)\" # zsh/bash');\n consola.info(' forgemap shell-init fish | source # fish');\n consola.info(\n 'Or, if you just want the path on stdout, use: forgemap path <slug>'\n );\n process.exitCode = 1;\n }\n});\n","import { homedir } from 'node:os';\nimport { isAbsolute, resolve } from 'pathe';\n\nexport function expandTilde(p: string): string {\n if (p === '~') return homedir();\n if (p.startsWith('~/')) return resolve(homedir(), p.slice(2));\n return p;\n}\n\nexport function resolveRoot(root: string, configDir: string): string {\n const expanded = expandTilde(root);\n if (isAbsolute(expanded)) return expanded;\n return resolve(configDir, expanded);\n}\n","import { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { loadConfig } from 'c12';\nimport { dirname, join, resolve } from 'pathe';\nimport type { ForgeMapConfig, ForgeMapUserConfig } from './schema.ts';\n\nconst CONFIG_BASENAMES = [\n 'forgemap.config.ts',\n 'forgemap.config.mts',\n 'forgemap.config.cts',\n 'forgemap.config.js',\n 'forgemap.config.mjs',\n 'forgemap.config.cjs',\n 'forgemap.config.json'\n];\n\n/** Walk up from `start` to the filesystem root looking for a forgemap config. */\nfunction findConfigUp(start: string): string | undefined {\n let dir = resolve(start);\n for (;;) {\n for (const base of CONFIG_BASENAMES) {\n const candidate = join(dir, base);\n if (existsSync(candidate)) return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n}\n\n/** Fallback config under $XDG_CONFIG_HOME/forgemap (or ~/.config/forgemap). */\nfunction findGlobalConfig(): string | undefined {\n const base = process.env.XDG_CONFIG_HOME || join(homedir(), '.config');\n const dir = join(base, 'forgemap');\n for (const baseName of CONFIG_BASENAMES) {\n const candidate = join(dir, baseName);\n if (existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n\nexport interface ConfigFileCandidate {\n path: string;\n /** Which discovery step surfaced it. */\n source: 'walk-up' | 'global';\n}\n\n/**\n * Every `forgemap.config.*` a change could be written to, in resolution order:\n * one per directory walking up from `start` (nearest first, mirroring the\n * loader's first-basename-wins rule), then the global config. Used by the\n * `forge` command to let the user pick a target when more than one exists.\n */\nexport function discoverConfigFiles(\n start: string = process.cwd()\n): ConfigFileCandidate[] {\n const found: ConfigFileCandidate[] = [];\n const seen = new Set<string>();\n let dir = resolve(start);\n for (;;) {\n for (const base of CONFIG_BASENAMES) {\n const candidate = join(dir, base);\n if (existsSync(candidate)) {\n seen.add(candidate);\n found.push({ path: candidate, source: 'walk-up' });\n break;\n }\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n const global = findGlobalConfig();\n if (global && !seen.has(global)) {\n found.push({ path: global, source: 'global' });\n }\n return found;\n}\n\n/**\n * Which of the four discovery steps produced the resolved config file:\n * `--config` flag → `FORGEMAP_CONFIG` env → walk-up from cwd → global fallback.\n * `default` means none matched and the built-in defaults are in effect.\n */\nexport type ConfigSource = 'flag' | 'env' | 'walk-up' | 'global' | 'default';\n\nexport interface LoadedConfig {\n config: ForgeMapConfig;\n configFile: string | undefined;\n cwd: string;\n /** The discovery step that found `configFile`, or `default` when none did. */\n source: ConfigSource;\n}\n\nconst DEFAULT_CONFIG: ForgeMapConfig = {\n root: '.',\n defaultForge: 'github',\n forges: {\n github: {\n type: 'github',\n host: 'github.com',\n dir: 'comGithub'\n }\n }\n};\n\nexport interface LoadOptions {\n cwd?: string;\n configFile?: string;\n}\n\nexport async function loadForgeMapConfig(\n options: LoadOptions = {}\n): Promise<LoadedConfig> {\n const envConfig = process.env.FORGEMAP_CONFIG;\n const startDir = options.cwd ?? process.cwd();\n // Resolution order: explicit flag → env → walk up from cwd → global fallback.\n // Track which step matched so callers (e.g. `info`) can report the origin.\n let explicit: string | undefined;\n let source: ConfigSource;\n if (options.configFile) {\n explicit = options.configFile;\n source = 'flag';\n } else if (envConfig) {\n explicit = envConfig;\n source = 'env';\n } else {\n const walkedUp = findConfigUp(startDir);\n if (walkedUp) {\n explicit = walkedUp;\n source = 'walk-up';\n } else {\n const global = findGlobalConfig();\n if (global) {\n explicit = global;\n source = 'global';\n } else {\n explicit = undefined;\n source = 'default';\n }\n }\n }\n // Resolve before handing it to c12 — `cwd` is derived from it, so a relative\n // path would be resolved a second time against that cwd and end up nested.\n if (explicit) explicit = resolve(startDir, explicit);\n const cwd = explicit ? dirname(explicit) : startDir;\n\n // No `defaults:` here — c12 would deep-merge them into the user\n // config (forges in particular), which surfaces the built-in github\n // forge in every custom layout. We apply defaults below ourselves,\n // only filling in missing top-level fields.\n const { config, configFile } = await loadConfig<ForgeMapUserConfig>({\n name: 'forgemap',\n cwd,\n configFile: explicit ? explicit : 'forgemap.config',\n rcFile: false,\n globalRc: false,\n dotenv: false\n });\n\n // User-defined forges replace the defaults entirely — otherwise the\n // built-in github fallback would pollute every custom config and\n // commands like `validate` would demand `gh` even when no github\n // forge is configured.\n const merged: ForgeMapConfig = {\n root: config.root ?? DEFAULT_CONFIG.root,\n defaultForge: config.defaultForge ?? DEFAULT_CONFIG.defaultForge,\n forges:\n config.forges && Object.keys(config.forges).length > 0\n ? config.forges\n : DEFAULT_CONFIG.forges\n };\n\n // When nothing was discovered, c12 still echoes back the fallback base name\n // (\"forgemap.config\") as `configFile` — a path that does not exist. Treat that\n // as \"no file\" so callers report the built-in defaults honestly.\n const resolvedFile =\n source === 'default' ? undefined : configFile || undefined;\n\n return {\n config: merged,\n configFile: resolvedFile,\n cwd,\n source: resolvedFile ? source : 'default'\n };\n}\n","import { readdir } from 'node:fs/promises';\nimport { join } from 'pathe';\nimport type { ForgeConfig, ForgeMapConfig } from '../config/schema.ts';\nimport { resolveRoot } from '../utils/path.ts';\n\nexport interface ScannedRepo {\n forgeName: string;\n forge: ForgeConfig;\n owner: string;\n repo: string;\n localPath: string;\n /** Convenience: `<owner>/<repo>` */\n slug: string;\n}\n\nasync function listDirs(path: string): Promise<string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => e.name);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw error;\n }\n}\n\nexport interface ScanOptions {\n config: ForgeMapConfig;\n configDir: string;\n}\n\nexport async function scanRepos(options: ScanOptions): Promise<ScannedRepo[]> {\n const { config, configDir } = options;\n const root = resolveRoot(config.root, configDir);\n const repos: ScannedRepo[] = [];\n\n for (const [forgeName, forge] of Object.entries(config.forges)) {\n const forgeRoot = join(root, forge.dir);\n const owners = await listDirs(forgeRoot);\n for (const owner of owners) {\n const ownerPath = join(forgeRoot, owner);\n const repoNames = await listDirs(ownerPath);\n for (const repo of repoNames) {\n repos.push({\n forgeName,\n forge,\n owner,\n repo,\n localPath: join(ownerPath, repo),\n slug: `${owner}/${repo}`\n });\n }\n }\n }\n\n return repos;\n}\n","import { createHash } from 'node:crypto';\nimport { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'pathe';\nimport type { ForgeMapConfig } from '../config/schema.ts';\nimport { resolveRoot } from '../utils/path.ts';\nimport { type ScannedRepo, scanRepos } from './scan.ts';\n\n/**\n * Cache lifecycle:\n *\n * 1. Hot path (age < TTL): trust the file, return repos directly.\n * No stat calls, no fingerprint walk — ~1 ms.\n *\n * 2. Cold path (age ≥ TTL): walk depth-3 mtimes (in parallel) and\n * compare against the stored fingerprint. On match, bump the\n * timestamp and return cached repos. On mismatch, rescan and\n * rewrite the cache.\n *\n * 3. Incremental updates (appendCachedRepo / removeCachedRepo):\n * forgemap-driven changes (clone, remove) edit the cache in-place\n * so the next read stays on the hot path. Used to skip rebuild\n * when forgemap itself is the source of truth.\n *\n * Set FORGEMAP_CACHE_TTL_MS (default 60 000) to override the TTL.\n */\ninterface CacheFile {\n fingerprint: string;\n writtenAt: number;\n repos: ScannedRepo[];\n}\n\nconst DEFAULT_TTL_MS = 60_000;\n\nfunction ttl(): number {\n const env = process.env.FORGEMAP_CACHE_TTL_MS;\n if (!env) return DEFAULT_TTL_MS;\n const parsed = Number.parseInt(env, 10);\n return Number.isFinite(parsed) && parsed >= 0 ? parsed : DEFAULT_TTL_MS;\n}\n\nfunction cacheDir(): string {\n const xdg = process.env.XDG_CACHE_HOME;\n return xdg ? join(xdg, 'forgemap') : join(homedir(), '.cache', 'forgemap');\n}\n\nfunction cachePath(root: string): string {\n const hash = createHash('sha1').update(root).digest('hex').slice(0, 16);\n return join(cacheDir(), `scan-${hash}.json`);\n}\n\nasync function safeStat(path: string): Promise<number> {\n try {\n const s = await stat(path);\n return Math.trunc(s.mtimeMs);\n } catch {\n return 0;\n }\n}\n\nasync function safeListDirs(path: string): Promise<string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => e.name);\n } catch {\n return [];\n }\n}\n\n/**\n * Fingerprint of every directory mtime down to depth 3 (root, forge.dir,\n * owner). Catches new clones / removals at any of those levels. Stops\n * short of stat-ing each repo dir — that would mostly duplicate the\n * scan it's meant to avoid.\n *\n * Stats are issued in parallel: one batch per forge for its forge.dir +\n * owner list, all forges in parallel. Beats the sequential version by\n * an order of magnitude at thousands of owners.\n */\nexport async function computeFingerprint(\n config: ForgeMapConfig,\n configDir: string\n): Promise<string> {\n const root = resolveRoot(config.root, configDir);\n\n const perForge = await Promise.all(\n Object.values(config.forges).map(async (forge) => {\n const forgeRoot = join(root, forge.dir);\n const [forgeMtime, owners] = await Promise.all([\n safeStat(forgeRoot),\n safeListDirs(forgeRoot)\n ]);\n const ownerEntries = await Promise.all(\n owners.map(async (owner) => {\n const ownerPath = join(forgeRoot, owner);\n return [ownerPath, await safeStat(ownerPath)] as [string, number];\n })\n );\n return [[forgeRoot, forgeMtime] as [string, number], ...ownerEntries];\n })\n );\n\n const entries: Array<[string, number]> = [[root, await safeStat(root)]];\n for (const group of perForge) entries.push(...group);\n\n entries.sort((a, b) => a[0].localeCompare(b[0]));\n return createHash('sha1')\n .update(entries.map(([p, m]) => `${p}:${m}`).join('\\n'))\n .digest('hex');\n}\n\nasync function readCacheFile(file: string): Promise<CacheFile | null> {\n try {\n const raw = await readFile(file, 'utf8');\n return JSON.parse(raw) as CacheFile;\n } catch {\n return null;\n }\n}\n\nasync function writeCacheFile(file: string, payload: CacheFile): Promise<void> {\n await mkdir(cacheDir(), { recursive: true });\n await writeFile(file, JSON.stringify(payload), 'utf8');\n}\n\nexport interface ScanCachedOptions {\n config: ForgeMapConfig;\n configDir: string;\n /** Default true. Set false to force a full re-scan and rewrite. */\n useCache?: boolean;\n /** Default true. Set false to skip the TTL fast-path and always validate the fingerprint. */\n trustTtl?: boolean;\n}\n\nexport async function scanReposCached(\n options: ScanCachedOptions\n): Promise<ScannedRepo[]> {\n const { config, configDir, useCache = true, trustTtl = true } = options;\n const root = resolveRoot(config.root, configDir);\n const file = cachePath(root);\n\n if (useCache) {\n const cached = await readCacheFile(file);\n if (cached) {\n const age = Date.now() - cached.writtenAt;\n if (trustTtl && age < ttl()) {\n return cached.repos;\n }\n const fingerprint = await computeFingerprint(config, configDir);\n if (cached.fingerprint === fingerprint) {\n // Still accurate — refresh the timestamp so the next reader can hot-path.\n await writeCacheFile(file, { ...cached, writtenAt: Date.now() });\n return cached.repos;\n }\n }\n }\n\n const repos = await scanRepos({ config, configDir });\n const fingerprint = await computeFingerprint(config, configDir);\n await writeCacheFile(file, {\n fingerprint,\n writtenAt: Date.now(),\n repos\n });\n return repos;\n}\n\n/**\n * Append a freshly-cloned repo to the cache without touching the\n * filesystem. Lets `forgemap clone` keep the cache warm so the next\n * read still hits the TTL fast-path.\n */\nexport async function appendCachedRepo(\n options: ScanCachedOptions,\n repo: ScannedRepo\n): Promise<void> {\n const { config, configDir } = options;\n const root = resolveRoot(config.root, configDir);\n const file = cachePath(root);\n const cached = await readCacheFile(file);\n if (!cached) {\n return; // no cache yet — next scan will pick the new repo up naturally\n }\n if (cached.repos.some((r) => r.localPath === repo.localPath)) {\n return;\n }\n await writeCacheFile(file, {\n fingerprint: await computeFingerprint(config, configDir),\n writtenAt: Date.now(),\n repos: [...cached.repos, repo]\n });\n}\n\n/**\n * Inverse of appendCachedRepo for a future `forgemap remove`.\n */\nexport async function removeCachedRepo(\n options: ScanCachedOptions,\n localPath: string\n): Promise<void> {\n const { config, configDir } = options;\n const root = resolveRoot(config.root, configDir);\n const file = cachePath(root);\n const cached = await readCacheFile(file);\n if (!cached) return;\n const next = cached.repos.filter((r) => r.localPath !== localPath);\n if (next.length === cached.repos.length) return;\n await writeCacheFile(file, {\n fingerprint: await computeFingerprint(config, configDir),\n writtenAt: Date.now(),\n repos: next\n });\n}\n\n// Exported for tests.\nexport const __test = { cacheDir, cachePath };\n","import { spawn } from 'node:child_process';\n\nexport interface ExecResult {\n code: number;\n}\n\nexport function execInherit(\n command: string,\n args: string[]\n): Promise<ExecResult> {\n return new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(command, args, { stdio: 'inherit' });\n child.on('error', rejectPromise);\n child.on('close', (code) => {\n resolvePromise({ code: code ?? 0 });\n });\n });\n}\n\nexport interface CaptureResult {\n code: number;\n stdout: string;\n stderr: string;\n /** True when the process was killed because it exceeded `timeoutMs`. */\n timedOut?: boolean;\n}\n\nexport interface CaptureOptions {\n cwd?: string;\n /** Kill the process after this many ms and resolve with `timedOut: true`. */\n timeoutMs?: number;\n /** Extra env vars, merged over `process.env`. */\n env?: NodeJS.ProcessEnv;\n}\n\nexport function execCapture(\n command: string,\n args: string[],\n options: CaptureOptions = {}\n): Promise<CaptureResult> {\n return new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n env: options.env ? { ...process.env, ...options.env } : undefined,\n stdio: ['ignore', 'pipe', 'pipe']\n });\n let stdout = '';\n let stderr = '';\n let timedOut = false;\n let settled = false;\n\n let timer: NodeJS.Timeout | undefined;\n let killer: NodeJS.Timeout | undefined;\n if (options.timeoutMs && options.timeoutMs > 0) {\n timer = setTimeout(() => {\n timedOut = true;\n child.kill('SIGTERM');\n // Escalate if it ignores SIGTERM (e.g. a wedged ssh child).\n killer = setTimeout(() => child.kill('SIGKILL'), 2000);\n killer.unref();\n }, options.timeoutMs);\n timer.unref();\n }\n\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n child.on('error', (error) => {\n if (timer) clearTimeout(timer);\n if (killer) clearTimeout(killer);\n if (!settled) {\n settled = true;\n rejectPromise(error);\n }\n });\n child.on('close', (code) => {\n if (timer) clearTimeout(timer);\n if (killer) clearTimeout(killer);\n if (!settled) {\n settled = true;\n // A signal kill reports code null; surface a non-zero code so callers\n // that only inspect `code` don't mistake a timeout for success.\n resolvePromise({\n code: code ?? (timedOut ? 124 : 0),\n stdout,\n stderr,\n timedOut\n });\n }\n });\n });\n}\n\nexport function hasCommand(command: string): Promise<boolean> {\n return new Promise((resolvePromise) => {\n const child = spawn(\n process.platform === 'win32' ? 'where' : 'which',\n [command],\n {\n stdio: 'ignore'\n }\n );\n child.on('error', () => resolvePromise(false));\n child.on('close', (code) => resolvePromise(code === 0));\n });\n}\n","import type {\n ForgeConfig,\n GitForgeConfig,\n GitProtocol\n} from '../config/schema.ts';\nimport { execCapture, execInherit, hasCommand } from '../utils/exec.ts';\nimport type {\n CloneOptions,\n ForgeAdapter,\n RemoteCheckInput,\n RemoteCheckResult\n} from './types.ts';\n\ninterface UrlParts {\n forge: ForgeConfig;\n owner: string;\n repo: string;\n protocol?: GitProtocol;\n}\n\nconst REMOTE_TIMEOUT_MS = 10_000;\n\nfunction buildCloneUrl(opts: UrlParts): string {\n const forge = opts.forge as GitForgeConfig;\n const protocol = opts.protocol ?? forge.protocol ?? 'ssh';\n if (protocol === 'https') {\n return `https://${forge.host}/${opts.owner}/${opts.repo}.git`;\n }\n return `git@${forge.host}:${opts.owner}/${opts.repo}.git`;\n}\n\nexport const gitAdapter: ForgeAdapter = {\n async clone(options: CloneOptions) {\n if (!(await hasCommand('git'))) {\n throw new Error(\n '`git` is not installed. Install it from https://git-scm.com/ and try again.'\n );\n }\n const url = buildCloneUrl(options);\n const { code } = await execInherit('git', ['clone', url, options.dest]);\n if (code !== 0) {\n throw new Error(`git clone exited with code ${code}`);\n }\n },\n\n async checkRemote(input: RemoteCheckInput): Promise<RemoteCheckResult> {\n if (!(await hasCommand('git'))) {\n return { state: 'unknown', reason: 'git not installed' };\n }\n // `git ls-remote` only proves reachability — it cannot detect a rename.\n // Force non-interactive SSH and a hard timeout so an unreachable or\n // auth-prompting host can't wedge the whole import.\n const url = input.originUrl ?? buildCloneUrl(input);\n const result = await execCapture('git', ['ls-remote', url], {\n timeoutMs: REMOTE_TIMEOUT_MS,\n env: {\n GIT_TERMINAL_PROMPT: '0',\n GIT_SSH_COMMAND: 'ssh -oBatchMode=yes -oConnectTimeout=5'\n }\n });\n if (result.timedOut) {\n return { state: 'unknown', reason: 'ls-remote timed out' };\n }\n if (result.code === 0) {\n return {\n state: 'exists',\n canonical: { owner: input.owner, repo: input.repo }\n };\n }\n // A failure is only `gone` when the host clearly says the repo is missing.\n // Unreachable hosts, auth failures, and the generic SSH error stay\n // `unknown` so we never falsely declare a repo deleted (the generic SSH\n // message even contains \"the repository exists\").\n if (isRepoMissing(result.stderr)) {\n return { state: 'gone' };\n }\n const reason =\n result.stderr\n .split('\\n')\n .map((line) => line.trim())\n .find(Boolean) ?? `git ls-remote exited with code ${result.code}`;\n return { state: 'unknown', reason };\n }\n};\n\n/** True only for an unambiguous \"this repository does not exist\" signal. */\nfunction isRepoMissing(stderr: string): boolean {\n const s = stderr.toLowerCase();\n return (\n /repository not found/.test(s) ||\n /remote:.*not found/.test(s) ||\n /\\b404\\b/.test(s) ||\n /could not find repository/.test(s)\n );\n}\n\n// Exported for testing.\nexport const __test = { buildCloneUrl, isRepoMissing };\n","/**\n * Map over `items` running at most `limit` calls of `fn` at once, preserving\n * input order in the result. Keeps `import` from spawning one subprocess per\n * repo all at once when checking remotes across a large tree.\n */\nexport async function mapLimit<T, R>(\n items: T[],\n limit: number,\n fn: (item: T, index: number) => Promise<R>\n): Promise<R[]> {\n const results: R[] = Array.from({ length: items.length });\n const max = Math.max(1, Math.min(limit, items.length));\n let next = 0;\n\n async function worker(): Promise<void> {\n while (next < items.length) {\n const index = next++;\n results[index] = await fn(items[index]!, index);\n }\n }\n\n await Promise.all(Array.from({ length: max }, () => worker()));\n return results;\n}\n","import { mapLimit } from '../utils/concurrency.ts';\nimport { execCapture, execInherit, hasCommand } from '../utils/exec.ts';\nimport type {\n CloneOptions,\n ForgeAdapter,\n RemoteCheckInput,\n RemoteCheckResult\n} from './types.ts';\n\nconst GRAPHQL_CHUNK = 100;\nconst FALLBACK_CONCURRENCY = 8;\nconst GH_TIMEOUT_MS = 20_000;\n\n/** Single-repo REST check. `gh api` follows the redirect a renamed/transferred\n * repo issues, so the returned full_name reveals the canonical owner/repo. */\nasync function checkOne(\n owner: string,\n repo: string\n): Promise<RemoteCheckResult> {\n const result = await execCapture(\n 'gh',\n ['api', `repos/${owner}/${repo}`, '--jq', '.full_name'],\n { timeoutMs: GH_TIMEOUT_MS }\n );\n if (result.timedOut) {\n return { state: 'unknown', reason: 'gh api timed out' };\n }\n if (result.code !== 0) {\n if (/404|not found/i.test(result.stderr)) return { state: 'gone' };\n return {\n state: 'unknown',\n reason: result.stderr.trim() || `gh api exited with code ${result.code}`\n };\n }\n const fullName = result.stdout.trim();\n const [canonicalOwner, canonicalRepo] = fullName.split('/');\n if (!canonicalOwner || !canonicalRepo) {\n return { state: 'unknown', reason: 'could not parse gh api full_name' };\n }\n const canonical = { owner: canonicalOwner, repo: canonicalRepo };\n if (canonicalOwner === owner && canonicalRepo === repo) {\n return { state: 'exists', canonical };\n }\n return {\n state: 'moved',\n canonical,\n canonicalUrl: `https://github.com/${canonicalOwner}/${canonicalRepo}.git`\n };\n}\n\nfunction buildQuery(chunk: RemoteCheckInput[]): string {\n const fields = chunk\n .map(\n (input, i) =>\n ` r${i}: repository(owner: ${JSON.stringify(input.owner)}, name: ${JSON.stringify(input.repo)}) { nameWithOwner }`\n )\n .join('\\n');\n return `query {\\n${fields}\\n}`;\n}\n\nexport const githubAdapter: ForgeAdapter = {\n async clone({ owner, repo, dest }: CloneOptions) {\n if (!(await hasCommand('gh'))) {\n throw new Error(\n 'GitHub CLI (`gh`) is not installed. Install it from https://cli.github.com/ and run `gh auth login`.'\n );\n }\n const { code } = await execInherit('gh', [\n 'repo',\n 'clone',\n `${owner}/${repo}`,\n dest\n ]);\n if (code !== 0) {\n throw new Error(`gh repo clone exited with code ${code}`);\n }\n },\n\n async checkRemote({\n owner,\n repo\n }: RemoteCheckInput): Promise<RemoteCheckResult> {\n if (!(await hasCommand('gh'))) {\n return { state: 'unknown', reason: 'gh not installed' };\n }\n return checkOne(owner, repo);\n },\n\n /**\n * One GraphQL request resolves up to GRAPHQL_CHUNK repos at once. GraphQL\n * does not follow rename redirects, so a hit means `exists`; a null/miss\n * could be either `gone` or `moved` and is disambiguated with a single\n * (redirect-following) REST call, run concurrency-limited.\n */\n async checkRemotes(inputs: RemoteCheckInput[]): Promise<RemoteCheckResult[]> {\n if (inputs.length === 0) return [];\n if (!(await hasCommand('gh'))) {\n return inputs.map(() => ({\n state: 'unknown',\n reason: 'gh not installed'\n }));\n }\n\n const results: (RemoteCheckResult | null)[] = Array.from(\n { length: inputs.length },\n () => null\n );\n\n for (let start = 0; start < inputs.length; start += GRAPHQL_CHUNK) {\n const chunk = inputs.slice(start, start + GRAPHQL_CHUNK);\n const res = await execCapture(\n 'gh',\n ['api', 'graphql', '-f', `query=${buildQuery(chunk)}`],\n { timeoutMs: GH_TIMEOUT_MS }\n );\n type GraphqlData = Record<string, { nameWithOwner?: string } | null>;\n let data: GraphqlData | null = null;\n try {\n data = (JSON.parse(res.stdout) as { data?: GraphqlData }).data ?? null;\n } catch {\n data = null;\n }\n for (let i = 0; i < chunk.length; i++) {\n const node = data?.[`r${i}`];\n if (node?.nameWithOwner) {\n const [owner, repo] = node.nameWithOwner.split('/');\n if (owner && repo) {\n results[start + i] = {\n state: 'exists',\n canonical: { owner, repo }\n };\n }\n }\n // Left null → resolved via REST fallback below.\n }\n }\n\n const pending = results.flatMap((r, i) => (r === null ? [i] : []));\n await mapLimit(pending, FALLBACK_CONCURRENCY, async (index) => {\n results[index] = await checkOne(\n inputs[index]!.owner,\n inputs[index]!.repo\n );\n });\n\n return results as RemoteCheckResult[];\n }\n};\n","import type { ForgeType } from '../config/schema.ts';\nimport { gitAdapter } from './git.ts';\nimport { githubAdapter } from './github.ts';\nimport type { ForgeAdapter } from './types.ts';\n\nexport function getForgeAdapter(type: ForgeType): ForgeAdapter {\n switch (type) {\n case 'github':\n return githubAdapter;\n case 'git':\n return gitAdapter;\n case 'gitlab':\n case 'gitea':\n case 'codeberg':\n throw new Error(\n `Forge type \"${type}\" is not implemented yet. Use type: 'git' for a vanilla git-clone fallback.`\n );\n default: {\n const exhaustive: never = type;\n throw new Error(`Unknown forge type: ${String(exhaustive)}`);\n }\n }\n}\n","export interface ParsedSlug {\n /** Forge alias if explicitly specified via `<forge>:<owner>/<repo>` */\n forgeName?: string;\n /** Host if extracted from URL/SSH form */\n host?: string;\n owner: string;\n repo: string;\n}\n\nconst SHORT_RE = /^([\\w.-]+)\\/([\\w.-]+)$/;\nconst NAMED_RE = /^([\\w.-]+):([\\w.-]+)\\/([\\w.-]+)$/;\nconst SSH_RE = /^git@([\\w.-]+):([\\w.-]+)\\/([\\w.-]+?)(?:\\.git)?$/;\n\nfunction stripGitSuffix(repo: string): string {\n return repo.endsWith('.git') ? repo.slice(0, -4) : repo;\n}\n\n/**\n * Whether the input is *shaped* like a strict slug. Every form\n * {@link parseSlug} accepts — `owner/repo`, `forge:owner/repo`, SSH and\n * URL — contains a `/`, so a bare term like `gild` can never be one and is\n * free to be treated as a fuzzy query instead.\n *\n * Shaped-like is deliberately not the same as valid: `foo/bar/baz` is shaped\n * like a slug, so it stays a hard parse error rather than silently degrading\n * into a fuzzy search for something the user clearly meant as a slug.\n */\nexport function looksLikeSlug(input: string): boolean {\n return input.trim().includes('/');\n}\n\nexport function parseSlug(input: string): ParsedSlug {\n const trimmed = input.trim();\n if (!trimmed) {\n throw new Error('Slug is empty');\n }\n\n // git@host:owner/repo(.git)\n const ssh = SSH_RE.exec(trimmed);\n if (ssh) {\n return {\n host: ssh[1],\n owner: ssh[2]!,\n repo: stripGitSuffix(ssh[3]!)\n };\n }\n\n // https://host/owner/repo(.git) or http://...\n if (/^https?:\\/\\//.test(trimmed)) {\n let url: URL;\n try {\n url = new URL(trimmed);\n } catch {\n throw new Error(`Invalid URL: ${trimmed}`);\n }\n const segments = url.pathname.split('/').filter(Boolean);\n if (segments.length < 2) {\n throw new Error(`URL must contain owner and repo: ${trimmed}`);\n }\n return {\n host: url.host,\n owner: segments[0]!,\n repo: stripGitSuffix(segments[1]!)\n };\n }\n\n // forge:owner/repo\n const named = NAMED_RE.exec(trimmed);\n if (named) {\n return {\n forgeName: named[1],\n owner: named[2]!,\n repo: stripGitSuffix(named[3]!)\n };\n }\n\n // owner/repo\n const short = SHORT_RE.exec(trimmed);\n if (short) {\n return {\n owner: short[1]!,\n repo: stripGitSuffix(short[2]!)\n };\n }\n\n throw new Error(`Unrecognized slug format: ${input}`);\n}\n","import { execCapture, type CaptureResult } from '../utils/exec.ts';\n\nexport interface RepoStatus {\n branch: string;\n /** No upstream configured for the current branch. */\n detached: boolean;\n dirty: boolean;\n ahead: number;\n behind: number;\n /** Entries on `refs/stash` — local work no other field reports. */\n stashes: number;\n lastCommit: { sha: string; relativeDate: string } | null;\n}\n\nasync function gitIn(cwd: string, args: string[]): Promise<CaptureResult> {\n return execCapture('git', args, { cwd });\n}\n\n/** Network git ops (fetch/pull) must never block: force non-interactive SSH\n * and a hard timeout so an unreachable or auth-prompting remote can't wedge\n * a whole `sync` run. */\nconst NETWORK_TIMEOUT_MS = 30_000;\n\nasync function gitNetwork(cwd: string, args: string[]): Promise<CaptureResult> {\n return execCapture('git', args, {\n cwd,\n timeoutMs: NETWORK_TIMEOUT_MS,\n env: {\n GIT_TERMINAL_PROMPT: '0',\n GIT_SSH_COMMAND: 'ssh -oBatchMode=yes -oConnectTimeout=5'\n }\n });\n}\n\nexport async function getRepoStatus(localPath: string): Promise<RepoStatus> {\n const status: RepoStatus = {\n branch: 'HEAD',\n detached: false,\n dirty: false,\n ahead: 0,\n behind: 0,\n stashes: 0,\n lastCommit: null\n };\n\n const branchResult = await gitIn(localPath, ['branch', '--show-current']);\n status.branch = branchResult.stdout.trim() || 'HEAD';\n status.detached = !status.branch || status.branch === 'HEAD';\n\n const porcelain = await gitIn(localPath, ['status', '--porcelain']);\n status.dirty = porcelain.stdout.trim().length > 0;\n\n status.stashes = await countStashes(localPath);\n\n // ahead/behind only meaningful with an upstream\n const aheadBehind = await gitIn(localPath, [\n 'rev-list',\n '--left-right',\n '--count',\n '@{u}...HEAD'\n ]);\n if (aheadBehind.code === 0) {\n const match = aheadBehind.stdout.trim().match(/^(\\d+)\\s+(\\d+)$/);\n if (match) {\n status.behind = Number(match[1]);\n status.ahead = Number(match[2]);\n }\n }\n\n const lastCommit = await gitIn(localPath, ['log', '-1', '--format=%h|%cr']);\n if (lastCommit.code === 0) {\n const [sha, relativeDate] = lastCommit.stdout.trim().split('|');\n if (sha && relativeDate) {\n status.lastCommit = { sha, relativeDate };\n }\n }\n\n return status;\n}\n\nexport async function fetchRepo(localPath: string): Promise<CaptureResult> {\n return gitNetwork(localPath, ['fetch', '--all', '--prune']);\n}\n\nexport async function pullRepo(localPath: string): Promise<CaptureResult> {\n return gitNetwork(localPath, ['pull', '--ff-only']);\n}\n\nexport async function isClean(localPath: string): Promise<boolean> {\n const result = await gitIn(localPath, ['status', '--porcelain']);\n return result.code === 0 && result.stdout.trim().length === 0;\n}\n\nexport interface GitRemote {\n name: string;\n url: string;\n}\n\n/** True if `localPath` is inside a git work tree. */\nexport async function isGitRepo(localPath: string): Promise<boolean> {\n const result = await gitIn(localPath, ['rev-parse', '--is-inside-work-tree']);\n return result.code === 0 && result.stdout.trim() === 'true';\n}\n\n/** The `origin` remote URL, or null when there is no `origin`. */\nexport async function getOriginUrl(localPath: string): Promise<string | null> {\n const result = await gitIn(localPath, ['remote', 'get-url', 'origin']);\n if (result.code !== 0) return null;\n const url = result.stdout.trim();\n return url.length > 0 ? url : null;\n}\n\n/** Every configured remote with a URL, in config order. */\nexport async function getRemotes(localPath: string): Promise<GitRemote[]> {\n const result = await gitIn(localPath, [\n 'config',\n '--get-regexp',\n '^remote\\\\..*\\\\.url$'\n ]);\n if (result.code !== 0) return [];\n const remotes: GitRemote[] = [];\n for (const line of result.stdout.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n const match = trimmed.match(/^remote\\.(.+)\\.url\\s+(.+)$/);\n if (match) remotes.push({ name: match[1]!, url: match[2]! });\n }\n return remotes;\n}\n\n/** Repoint `origin` at a new URL. Used by `import --fix`. */\nexport async function setOriginUrl(\n localPath: string,\n url: string\n): Promise<CaptureResult> {\n return gitIn(localPath, ['remote', 'set-url', 'origin', url]);\n}\n\n/** Unix timestamp (seconds) of the most recent commit on a LOCAL branch, or\n * null when there are no commits. Excludes remote-tracking refs on purpose:\n * a recent `fetch` must not make a long-idle local checkout look fresh.\n * Drives the staleness check in `cleanup`. */\nexport async function getLastCommitUnix(\n localPath: string\n): Promise<number | null> {\n const result = await gitIn(localPath, [\n 'log',\n '--branches',\n '-1',\n '--format=%ct'\n ]);\n if (result.code !== 0) return null;\n const ts = Number.parseInt(result.stdout.trim(), 10);\n return Number.isFinite(ts) ? ts : null;\n}\n\n/**\n * True when any commit on any local branch is not reachable from a remote\n * tracking ref — i.e. there is work that exists only locally. Conservative\n * by design: with no remotes configured, everything counts as unpushed.\n */\nexport async function hasUnpushedCommits(localPath: string): Promise<boolean> {\n const result = await gitIn(localPath, [\n 'log',\n '--branches',\n '--not',\n '--remotes',\n '--format=%H',\n '-1'\n ]);\n if (result.code !== 0) return true;\n return result.stdout.trim().length > 0;\n}\n\n/**\n * The local branches that carry commits existing on no remote — the concrete\n * work behind `hasUnpushedCommits`'s boolean. Reporting only: `delete` names\n * them so the user sees what a deletion would actually destroy, rather than\n * just being told \"unpushed commits\". Returns [] when nothing is unpushed or\n * the branch list cannot be read.\n */\nexport async function getUnpushedBranches(\n localPath: string\n): Promise<string[]> {\n const listed = await gitIn(localPath, [\n 'for-each-ref',\n '--format=%(refname:short)',\n 'refs/heads'\n ]);\n if (listed.code !== 0) return [];\n\n const branches = listed.stdout\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean);\n\n const unpushed: string[] = [];\n for (const branch of branches) {\n const result = await gitIn(localPath, [\n 'log',\n branch,\n '--not',\n '--remotes',\n '--format=%H',\n '-1'\n ]);\n if (result.code === 0 && result.stdout.trim().length > 0) {\n unpushed.push(branch);\n }\n }\n return unpushed;\n}\n\n/**\n * Number of entries on the stash. Stashed work is invisible to every other\n * local check: `git status --porcelain` reports no working-tree change once\n * the stash is taken, and stash commits live on `refs/stash`, so\n * `git log --branches` (staleness) and `--branches --not --remotes`\n * (unpushed) skip them too. A repo whose only local work is stashed therefore\n * looks clean, idle and fully pushed unless this is checked explicitly.\n *\n * `%gd` prints one bare `stash@{n}` per entry, so a stash message containing\n * a newline cannot inflate the count. Returns 0 when the stash is unreadable\n * (e.g. not a git repo) — callers gate on `isGitRepo` first.\n */\nexport async function countStashes(localPath: string): Promise<number> {\n const result = await gitIn(localPath, ['stash', 'list', '--format=%gd']);\n if (result.code !== 0) return 0;\n return result.stdout.split('\\n').filter((line) => line.trim().length > 0)\n .length;\n}\n\n/** True when the repo has any stashed work. See {@link countStashes}. */\nexport async function hasStashes(localPath: string): Promise<boolean> {\n return (await countStashes(localPath)) > 0;\n}\n","import { readdir, rmdir } from 'node:fs/promises';\nimport { join } from 'pathe';\nimport type { ForgeMapConfig, ForgeType } from '../config/schema.ts';\nimport { getForgeAdapter } from '../forges/registry.ts';\nimport type { RemoteCheckInput, RemoteCheckResult } from '../forges/types.ts';\nimport { parseSlug } from '../slug/parse.ts';\nimport { mapLimit } from '../utils/concurrency.ts';\nimport {\n getLastCommitUnix,\n getOriginUrl,\n getRepoStatus,\n hasUnpushedCommits,\n isGitRepo\n} from './git.ts';\nimport type { ScannedRepo } from './scan.ts';\n\nconst REMOTE_CONCURRENCY = 10;\n\n/**\n * A deletion candidate: a git repo that has an origin. `dirty` / `unpushed` /\n * `stashes` record its local state; the gates below decide whether those block\n * deletion (overridable via flags) while a missing remote is always a hard stop.\n * Carries the origin identity used for the remote-existence check.\n *\n * Shared by `cleanup` (bulk, staleness-driven) and `delete` (targeted) so the\n * two commands cannot drift apart on what counts as safe to remove.\n */\nexport interface RepoEvaluation {\n repo: ScannedRepo;\n origin: string;\n /** owner/repo parsed from origin (falls back to the folder identity). */\n owner: string;\n name: string;\n /** Newest commit on a local branch; null when the repo has no commits. */\n lastCommitUnix: number | null;\n dirty: boolean;\n unpushed: boolean;\n /** Entries on the stash; deleting the repo destroys them. */\n stashes: number;\n}\n\n/** A `RepoEvaluation` that passed a staleness cutoff, so its last commit is known. */\nexport interface StaleRepoEvaluation extends RepoEvaluation {\n lastCommitUnix: number;\n}\n\nexport interface EvaluateOptions {\n /**\n * Only return the repo when its newest local commit is at or before this\n * unix timestamp (and a repo with no commits at all is skipped). Omit to\n * evaluate regardless of age — `delete` targets one repo by name and has no\n * staleness requirement.\n */\n cutoffUnix?: number;\n}\n\nexport async function evaluateRepo(\n repo: ScannedRepo,\n options: { cutoffUnix: number }\n): Promise<StaleRepoEvaluation | null>;\nexport async function evaluateRepo(\n repo: ScannedRepo,\n options?: EvaluateOptions\n): Promise<RepoEvaluation | null>;\n/**\n * Local gates (no network). Returns null for repos we ignore entirely:\n * non-git dirs, repos without an origin, and — when `cutoffUnix` is given —\n * repos that are NOT stale (their newest local commit is within the cutoff).\n * Anything returned carries its dirty/unpushed/stashed state.\n */\nexport async function evaluateRepo(\n repo: ScannedRepo,\n options: EvaluateOptions = {}\n): Promise<RepoEvaluation | null> {\n if (!(await isGitRepo(repo.localPath))) return null;\n const origin = await getOriginUrl(repo.localPath);\n if (!origin) return null;\n\n const lastCommitUnix = await getLastCommitUnix(repo.localPath);\n if (options.cutoffUnix !== undefined) {\n if (lastCommitUnix === null || lastCommitUnix > options.cutoffUnix) {\n return null;\n }\n }\n\n const status = await getRepoStatus(repo.localPath);\n const dirty = status.dirty;\n const stashes = status.stashes;\n const unpushed = await hasUnpushedCommits(repo.localPath);\n\n let owner = repo.owner;\n let name = repo.repo;\n try {\n const parsed = parseSlug(origin);\n owner = parsed.owner;\n name = parsed.repo;\n } catch {\n // Unparseable origin — fall back to the folder identity.\n }\n\n return {\n repo,\n origin,\n owner,\n name,\n lastCommitUnix,\n dirty,\n unpushed,\n stashes\n };\n}\n\n/** Which local-work gates the caller has explicitly opted to override. */\nexport interface GateOverrides {\n includeDirty: boolean;\n includeUnpushed: boolean;\n includeStashed: boolean;\n}\n\nconst UNCOMMITTED = 'uncommitted changes';\nconst UNPUSHED = 'unpushed commits';\nconst STASHED = 'stashed work';\n\n/** Stashes are separate work, so `--include-dirty` must not override them. */\nfunction stashedReason(stashes: number): string {\n return `${STASHED} (${stashes} stash${stashes === 1 ? '' : 'es'})`;\n}\n\n/**\n * The flag that lets a caller override a local gate, or undefined for a gate\n * that cannot be overridden. Lives beside `localBlocker` so a gate and its\n * escape hatch cannot drift apart; `delete` reads it to tell the user which\n * flag would force the deletion through.\n *\n * A function rather than a lookup table because the stashed-work reason\n * carries its count, so it has no fixed key.\n */\nexport function localGateOverride(reason: string): string | undefined {\n if (reason === UNCOMMITTED) return '--include-dirty';\n if (reason === UNPUSHED) return '--include-unpushed';\n if (reason.startsWith(STASHED)) return '--include-stashed';\n return undefined;\n}\n\n/**\n * Why this repo must not be deleted on local grounds, or null when every\n * local gate passes. The single place `cleanup` and `delete` agree on what\n * counts as local work at risk — a new gate added here reaches both commands.\n */\nexport function localBlocker(\n evaluation: RepoEvaluation,\n overrides: GateOverrides\n): string | null {\n if (evaluation.dirty && !overrides.includeDirty) return UNCOMMITTED;\n if (evaluation.unpushed && !overrides.includeUnpushed) return UNPUSHED;\n if (evaluation.stashes > 0 && !overrides.includeStashed) {\n return stashedReason(evaluation.stashes);\n }\n return null;\n}\n\n/**\n * Why the remote's state forbids deletion, or null when it is safe. A remote\n * that is gone or unreachable is ALWAYS a hard stop — no flag overrides it,\n * because the local copy may be the last one in existence.\n */\nexport function remoteBlocker(\n state: RemoteCheckResult['state'] | undefined\n): string | null {\n if (state === 'exists' || state === 'moved') return null;\n return state === 'gone' ? 'remote no longer exists' : 'remote unreachable';\n}\n\n/** Check each candidate's remote, grouped by forge so GitHub can batch. */\nexport async function classifyRemotes(\n candidates: RepoEvaluation[]\n): Promise<Map<string, RemoteCheckResult>> {\n const byType = new Map<ForgeType, RepoEvaluation[]>();\n for (const c of candidates) {\n const list = byType.get(c.repo.forge.type);\n if (list) list.push(c);\n else byType.set(c.repo.forge.type, [c]);\n }\n\n const results = new Map<string, RemoteCheckResult>();\n await Promise.all(\n Array.from(byType, async ([type, items]) => {\n const inputs: RemoteCheckInput[] = items.map((c) => ({\n forge: c.repo.forge,\n owner: c.owner,\n repo: c.name,\n originUrl: c.origin\n }));\n\n let adapter: ReturnType<typeof getForgeAdapter>;\n try {\n adapter = getForgeAdapter(type);\n } catch (error) {\n for (const c of items) {\n results.set(c.repo.localPath, {\n state: 'unknown',\n reason: (error as Error).message\n });\n }\n return;\n }\n\n let res: RemoteCheckResult[];\n if (adapter.checkRemotes) {\n try {\n res = await adapter.checkRemotes(inputs);\n } catch (error) {\n res = inputs.map(() => ({\n state: 'unknown',\n reason: (error as Error).message\n }));\n }\n } else if (adapter.checkRemote) {\n const check = adapter.checkRemote;\n res = await mapLimit(inputs, REMOTE_CONCURRENCY, async (inp) => {\n try {\n return await check(inp);\n } catch (error) {\n return { state: 'unknown', reason: (error as Error).message };\n }\n });\n } else {\n res = inputs.map(() => ({\n state: 'unknown',\n reason: `${type} has no remote check`\n }));\n }\n\n items.forEach((c, i) => results.set(c.repo.localPath, res[i]!));\n })\n );\n\n return results;\n}\n\nasync function safeReaddir(path: string): Promise<string[] | null> {\n try {\n return await readdir(path);\n } catch {\n return null;\n }\n}\n\n/** Empty owner directories (and a server directory that holds only such empty\n * owners) under the configured forge dirs. Detection only — no removal. */\nexport async function findEmptyDirs(\n root: string,\n config: ForgeMapConfig\n): Promise<string[]> {\n const empties: string[] = [];\n for (const forge of Object.values(config.forges)) {\n const serverPath = join(root, forge.dir);\n const owners = await safeReaddir(serverPath);\n if (owners === null) continue;\n let emptyCount = 0;\n for (const owner of owners) {\n const ownerPath = join(serverPath, owner);\n const inner = await safeReaddir(ownerPath);\n if (inner !== null && inner.length === 0) {\n empties.push(ownerPath);\n emptyCount++;\n }\n }\n // The server dir itself goes if it is empty or holds only empty owners.\n if (owners.length === 0 || emptyCount === owners.length) {\n empties.push(serverPath);\n }\n }\n return empties;\n}\n\n/** Remove the dirs from findEmptyDirs (owners before server dirs). */\nexport async function pruneEmptyDirs(\n root: string,\n config: ForgeMapConfig\n): Promise<number> {\n const empties = await findEmptyDirs(root, config);\n let removed = 0;\n for (const dir of empties) {\n try {\n await rmdir(dir);\n removed++;\n } catch {\n // Not actually empty (a file slipped in) — leave it.\n }\n }\n return removed;\n}\n","import { rm } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors } from 'consola/utils';\nimport { dirname } from 'pathe';\nimport { resolveRoot } from '../utils/path.ts';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { removeCachedRepo, scanReposCached } from '../repos/cache.ts';\nimport {\n classifyRemotes,\n evaluateRepo,\n findEmptyDirs,\n localBlocker,\n pruneEmptyDirs,\n remoteBlocker,\n type StaleRepoEvaluation\n} from '../repos/evaluate.ts';\nimport { mapLimit } from '../utils/concurrency.ts';\n\nconst DAY_SECONDS = 86_400;\nconst LOCAL_CONCURRENCY = 16;\n\nfunction ageDays(lastCommitUnix: number): number {\n return Math.floor(\n Date.now() / 1000 / DAY_SECONDS - lastCommitUnix / DAY_SECONDS\n );\n}\n\nexport const cleanupCommand = defineCommand({\n meta: {\n name: 'cleanup',\n description:\n 'List stale, clean, fully-pushed repos whose remote still exists, then delete them locally after confirmation'\n },\n args: {\n days: {\n type: 'string',\n description: 'Minimum age in days since the last commit (default 365)',\n default: '365'\n },\n forge: {\n type: 'string',\n description: 'Restrict to a single forge alias'\n },\n 'dry-run': {\n type: 'boolean',\n description: 'Only list candidates; never prompt or delete',\n default: false\n },\n yes: {\n type: 'boolean',\n description: 'Skip the interactive confirmation (deletes immediately)',\n default: false\n },\n 'include-dirty': {\n type: 'boolean',\n description:\n 'Also delete repos with uncommitted changes (those changes are lost)',\n default: false\n },\n 'include-unpushed': {\n type: 'boolean',\n description:\n 'Also delete repos with unpushed commits (those commits are lost)',\n default: false\n },\n 'include-stashed': {\n type: 'boolean',\n description: 'Also delete repos with stashed work (that stash is lost)',\n default: false\n },\n cache: {\n type: 'boolean',\n description: 'Use the scanned-repos cache',\n negativeDescription: 'Skip the scanned-repos cache',\n default: true\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const days = Number.parseInt(args.days, 10);\n if (!Number.isFinite(days) || days < 0) {\n consola.error(`Invalid --days value \"${args.days}\".`);\n process.exitCode = 1;\n return;\n }\n\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n let repos = await scanReposCached({\n config: loaded.config,\n configDir,\n useCache: args.cache\n });\n if (args.forge) repos = repos.filter((r) => r.forgeName === args.forge);\n\n const cutoffUnix = Math.floor(Date.now() / 1000) - days * DAY_SECONDS;\n\n // Stale repos that have an origin. (Recent repos and repos without an\n // origin are ignored entirely and never listed.)\n const stale = (\n await mapLimit(repos, LOCAL_CONCURRENCY, (repo) =>\n evaluateRepo(repo, { cutoffUnix })\n )\n ).filter((c): c is StaleRepoEvaluation => c !== null);\n\n const includeDirty = Boolean(args['include-dirty']);\n const includeUnpushed = Boolean(args['include-unpushed']);\n const includeStashed = Boolean(args['include-stashed']);\n const overrides = { includeDirty, includeUnpushed, includeStashed };\n\n // Dirty / unpushed / stashed only block when the matching --include flag\n // is off. A missing remote is ALWAYS a hard stop (never overridable). So\n // only the locally-eligible repos need a remote check.\n const remoteStates = await classifyRemotes(\n stale.filter((c) => localBlocker(c, overrides) === null)\n );\n\n const candidates: StaleRepoEvaluation[] = [];\n const kept: Array<{ repo: StaleRepoEvaluation; reason: string }> = [];\n for (const c of stale) {\n const reason =\n localBlocker(c, overrides) ??\n remoteBlocker(remoteStates.get(c.repo.localPath)?.state);\n if (reason === null) candidates.push(c);\n else kept.push({ repo: c, reason });\n }\n candidates.sort((a, b) => a.lastCommitUnix - b.lastCommitUnix);\n kept.sort((a, b) => a.repo.lastCommitUnix - b.repo.lastCommitUnix);\n\n if (candidates.length > 0) {\n process.stdout.write(\n `${colors.bold(`${candidates.length} repo(s) eligible for cleanup`)} ${colors.dim(`(idle ${days}+ days, remote exists)`)}\\n\\n`\n );\n for (const c of candidates) {\n const flags = [\n c.dirty ? colors.red('dirty') : '',\n c.unpushed ? colors.red('unpushed') : '',\n c.stashes > 0 ? colors.red(`stashed:${c.stashes}`) : ''\n ]\n .filter(Boolean)\n .join(' ');\n process.stdout.write(\n ` ${colors.cyan(`${c.repo.forgeName}:${c.repo.slug}`)} ${colors.dim(`${ageDays(c.lastCommitUnix)}d idle`)}${flags ? ` ${flags}` : ''} ${colors.dim(c.repo.localPath)}\\n`\n );\n }\n process.stdout.write('\\n');\n }\n\n // Explain why the other idle repos were spared.\n if (kept.length > 0) {\n process.stdout.write(\n `${colors.dim(`${kept.length} idle repo(s) kept (not safe to delete):`)}\\n`\n );\n for (const k of kept) {\n process.stdout.write(\n ` ${colors.dim(`${k.repo.repo.forgeName}:${k.repo.repo.slug} ${ageDays(k.repo.lastCommitUnix)}d idle — ${k.reason}`)}\\n`\n );\n }\n process.stdout.write('\\n');\n }\n\n const root = resolveRoot(loaded.config.root, configDir);\n\n // Empty owner/server directories (e.g. left behind by earlier deletions)\n // are tidied on every run — they hold no files, so this is non-destructive.\n if (args['dry-run']) {\n const empties = await findEmptyDirs(root, loaded.config);\n if (empties.length > 0) {\n process.stdout.write(\n `${colors.dim(`${empties.length} empty folder(s) would be removed:`)}\\n`\n );\n for (const e of empties) {\n process.stdout.write(` ${colors.dim(e)}\\n`);\n }\n process.stdout.write('\\n');\n }\n consola.info(\n candidates.length > 0\n ? 'Dry run — nothing deleted.'\n : 'Nothing to delete.'\n );\n return;\n }\n\n if (candidates.length > 0) {\n // Loud warning when --include flags put real work on the chopping block.\n const losing = candidates.filter(\n (c) => c.dirty || c.unpushed || c.stashes > 0\n ).length;\n if (losing > 0) {\n consola.warn(\n `${losing} of these have uncommitted/unpushed/stashed work that will be permanently lost.`\n );\n }\n\n let confirmed = args.yes;\n if (!confirmed) {\n const answer = await consola.prompt(\n `Type \"yes\" to delete these ${candidates.length} repo(s) locally:`,\n { type: 'text', cancel: 'null' }\n );\n confirmed = typeof answer === 'string' && answer.trim() === 'yes';\n }\n if (!confirmed) {\n consola.info('Aborted — nothing deleted.');\n return;\n }\n\n for (const c of candidates) {\n await rm(c.repo.localPath, { recursive: true, force: true });\n await removeCachedRepo(\n { config: loaded.config, configDir },\n c.repo.localPath\n );\n consola.success(`Deleted ${c.repo.localPath}`);\n }\n consola.success(`Removed ${candidates.length} repo(s).`);\n }\n\n // Sweep empty owner/server dirs (pre-existing + newly emptied by deletes).\n const emptied = await pruneEmptyDirs(root, loaded.config);\n if (emptied > 0) {\n consola.success(`Removed ${emptied} empty folder(s).`);\n } else if (candidates.length === 0) {\n consola.info('Nothing to clean up.');\n }\n }\n});\n","import { join } from 'pathe';\nimport type { ForgeConfig, ForgeMapConfig } from '../config/schema.ts';\nimport { resolveRoot } from '../utils/path.ts';\nimport type { ParsedSlug } from './parse.ts';\n\nexport interface ResolvedSlug {\n forgeName: string;\n forge: ForgeConfig;\n owner: string;\n repo: string;\n localPath: string;\n}\n\nexport interface ResolveOptions {\n config: ForgeMapConfig;\n configDir: string;\n}\n\nfunction findForgeByHost(\n forges: ForgeMapConfig['forges'],\n host: string\n): { name: string; forge: ForgeConfig } | undefined {\n for (const [name, forge] of Object.entries(forges)) {\n if (forge.host.toLowerCase() === host.toLowerCase()) {\n return { name, forge };\n }\n }\n return undefined;\n}\n\nexport function resolveSlug(\n parsed: ParsedSlug,\n options: ResolveOptions\n): ResolvedSlug {\n const { config, configDir } = options;\n\n let forgeName: string;\n let forge: ForgeConfig;\n\n if (parsed.forgeName) {\n const candidate = config.forges[parsed.forgeName];\n if (!candidate) {\n throw new Error(\n `Forge \"${parsed.forgeName}\" is not defined in forgemap.config`\n );\n }\n forgeName = parsed.forgeName;\n forge = candidate;\n } else if (parsed.host) {\n const match = findForgeByHost(config.forges, parsed.host);\n if (!match) {\n throw new Error(\n `No forge configured for host \"${parsed.host}\". Add it to forgemap.config.ts.`\n );\n }\n forgeName = match.name;\n forge = match.forge;\n } else {\n const candidate = config.forges[config.defaultForge];\n if (!candidate) {\n throw new Error(\n `Default forge \"${config.defaultForge}\" is not defined in forgemap.config`\n );\n }\n forgeName = config.defaultForge;\n forge = candidate;\n }\n\n const root = resolveRoot(config.root, configDir);\n const localPath = join(root, forge.dir, parsed.owner, parsed.repo);\n\n return {\n forgeName,\n forge,\n owner: parsed.owner,\n repo: parsed.repo,\n localPath\n };\n}\n","import { existsSync } from 'node:fs';\nimport { mkdir } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport type { GitProtocol } from '../config/schema.ts';\nimport { getForgeAdapter } from '../forges/registry.ts';\nimport { appendCachedRepo } from '../repos/cache.ts';\nimport { parseSlug } from '../slug/parse.ts';\nimport { resolveSlug } from '../slug/resolve.ts';\n\nexport const cloneCommand = defineCommand({\n meta: {\n name: 'clone',\n description: 'Clone a repo into the configured local layout'\n },\n args: {\n slug: {\n type: 'positional',\n description: 'owner/repo, forge:owner/repo, or full URL',\n required: true\n },\n ssh: {\n type: 'boolean',\n description: 'Force the SSH URL form (git-type forges only)',\n default: false\n },\n https: {\n type: 'boolean',\n description: 'Force the HTTPS URL form (git-type forges only)',\n default: false\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n if (args.ssh && args.https) {\n consola.error('--ssh and --https are mutually exclusive.');\n process.exitCode = 1;\n return;\n }\n\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const parsed = parseSlug(args.slug);\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const resolved = resolveSlug(parsed, {\n config: loaded.config,\n configDir\n });\n\n let protocol: GitProtocol | undefined;\n if (args.ssh) protocol = 'ssh';\n else if (args.https) protocol = 'https';\n\n if (protocol && resolved.forge.type !== 'git') {\n consola.warn(\n `--${protocol} is ignored for type \"${resolved.forge.type}\" — the adapter selects the URL itself.`\n );\n protocol = undefined;\n }\n\n if (existsSync(resolved.localPath)) {\n consola.info(`Already cloned at ${resolved.localPath}`);\n return;\n }\n\n await mkdir(dirname(resolved.localPath), { recursive: true });\n\n const adapter = getForgeAdapter(resolved.forge.type);\n await adapter.clone({\n forge: resolved.forge,\n owner: resolved.owner,\n repo: resolved.repo,\n dest: resolved.localPath,\n protocol\n });\n\n // Keep the scan cache hot so the next `list`/`cd`/`status` doesn't\n // pay for an invalidation walk just because we added one repo.\n await appendCachedRepo(\n { config: loaded.config, configDir },\n {\n forgeName: resolved.forgeName,\n forge: resolved.forge,\n owner: resolved.owner,\n repo: resolved.repo,\n localPath: resolved.localPath,\n slug: `${resolved.owner}/${resolved.repo}`\n }\n );\n\n consola.success(\n `Cloned ${resolved.owner}/${resolved.repo} → ${resolved.localPath}`\n );\n }\n});\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'pathe';\n\nexport type Shell = 'zsh' | 'bash' | 'fish';\n\nexport const SUPPORTED_SHELLS: Shell[] = ['zsh', 'bash', 'fish'];\n\nexport function detectShell(): Shell {\n const env = process.env.SHELL ?? '';\n if (env.endsWith('/fish')) return 'fish';\n if (env.endsWith('/bash')) return 'bash';\n return 'zsh';\n}\n\nexport function rcFileFor(shell: Shell): string {\n const home = homedir();\n if (shell === 'fish') return join(home, '.config', 'fish', 'config.fish');\n if (shell === 'bash') return join(home, '.bashrc');\n return join(home, '.zshrc');\n}\n\nexport type InstallResult =\n | { status: 'installed'; rcFile: string }\n | { status: 'updated'; rcFile: string }\n | { status: 'present'; rcFile: string };\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** Strip every marker-guarded block for any of `labels` from `content`. */\nfunction stripBlocks(content: string, labels: string[]): string {\n let out = content;\n for (const label of labels) {\n const l = escapeRegExp(label);\n const re = new RegExp(\n `\\\\n*# >>> forgemap ${l} >>>[\\\\s\\\\S]*?# <<< forgemap ${l} <<<\\\\n?`,\n 'g'\n );\n out = out.replace(re, '');\n }\n return out;\n}\n\n/**\n * Install a marker-guarded block of lines into the shell's rc file. `label`\n * namespaces the markers so independent features don't clash; `legacyLabels`\n * are older labels this feature used to write — they're removed too, so a\n * label rename never leaves a stale duplicate behind. Idempotent: re-running\n * collapses any existing/legacy blocks into a single current one.\n */\nexport async function installRcBlock(\n shell: Shell,\n label: string,\n lines: string[],\n legacyLabels: string[] = []\n): Promise<InstallResult> {\n const rcFile = rcFileFor(shell);\n let existing = '';\n try {\n existing = await readFile(rcFile, 'utf8');\n } catch {\n // rc file doesn't exist yet — we'll create it.\n }\n\n const allLabels = [label, ...legacyLabels];\n const hadAny = allLabels.some((l) =>\n existing.includes(`# >>> forgemap ${l} >>>`)\n );\n\n const block = `# >>> forgemap ${label} >>>\\n${lines.join('\\n')}\\n# <<< forgemap ${label} <<<\\n`;\n const cleaned = stripBlocks(existing, allLabels).replace(/\\s*$/, '');\n const next = cleaned.length > 0 ? `${cleaned}\\n\\n${block}` : block;\n\n if (next === existing) {\n return { status: 'present', rcFile };\n }\n await mkdir(dirname(rcFile), { recursive: true });\n await writeFile(rcFile, next, 'utf8');\n return { status: hadAny ? 'updated' : 'installed', rcFile };\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'pathe';\nimport type { ForgeConfig, ForgeMapConfig } from './schema.ts';\n\nconst HEADER = `/**\n * forgemap configuration.\n *\n * For type-safe authoring, install forgemap and switch to:\n * import { defineForgeMapConfig } from 'forgemap/config';\n * export default defineForgeMapConfig({ ... });\n *\n * @type {import('forgemap').ForgeMapUserConfig}\n */`;\n\n/** Quote a forge key unless it's already a bare JS identifier. */\nfunction quoteKey(name: string): string {\n return /^[A-Za-z_$][\\w$]*$/.test(name) ? name : `'${name}'`;\n}\n\nfunction renderForge(forge: ForgeConfig): string {\n const lines = [\n ` type: '${forge.type}',`,\n ` host: '${forge.host}',`,\n ` dir: '${forge.dir}'`\n ];\n if (forge.type === 'git' && forge.protocol) {\n lines.splice(1, 0, ` protocol: '${forge.protocol}',`);\n }\n return `{\\n${lines.join('\\n')}\\n }`;\n}\n\n/** Serialize a config to a `forgemap.config.ts` module body. */\nexport function renderConfigModule(config: ForgeMapConfig): string {\n const forgeEntries = Object.entries(config.forges)\n .map(([name, forge]) => ` ${quoteKey(name)}: ${renderForge(forge)}`)\n .join(',\\n');\n return `${HEADER}\nexport default {\n root: '${config.root}',\n defaultForge: '${config.defaultForge}',\n forges: {\n${forgeEntries}\n }\n};\n`;\n}\n\nexport interface WriteConfigOptions {\n outDir: string;\n force?: boolean;\n}\n\n/** Write a `forgemap.config.ts` into `outDir`. Returns null when the file\n * already exists and `force` is not set (the caller decides how to report). */\nexport async function writeConfigFile(\n config: ForgeMapConfig,\n options: WriteConfigOptions\n): Promise<{ path: string } | null> {\n const outDir = resolve(process.cwd(), options.outDir);\n const target = join(outDir, 'forgemap.config.ts');\n await mkdir(dirname(target), { recursive: true });\n try {\n await writeFile(target, renderConfigModule(config), {\n encoding: 'utf8',\n flag: options.force ? 'w' : 'wx'\n });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'EEXIST') {\n return null;\n }\n throw error;\n }\n return { path: target };\n}\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { join, resolve } from 'pathe';\nimport type { ForgeMapConfig } from '../../config/schema.ts';\nimport { writeConfigFile } from '../../config/write.ts';\n\nconst DEFAULT_CONFIG: ForgeMapConfig = {\n root: '.',\n defaultForge: 'github',\n forges: {\n github: {\n type: 'github',\n host: 'github.com',\n dir: 'comGithub'\n }\n }\n};\n\nexport const configInitCommand = defineCommand({\n meta: {\n name: 'init',\n description:\n 'Create a forgemap.config.ts in the current (or given) directory'\n },\n args: {\n out: {\n type: 'string',\n description: 'Directory to write forgemap.config.ts into',\n default: '.'\n },\n force: {\n type: 'boolean',\n description: 'Overwrite if forgemap.config.ts already exists',\n default: false\n }\n },\n async run({ args }) {\n const result = await writeConfigFile(DEFAULT_CONFIG, {\n outDir: args.out,\n force: args.force\n });\n\n if (!result) {\n const target = join(\n resolve(process.cwd(), args.out),\n 'forgemap.config.ts'\n );\n consola.error(`${target} already exists. Use --force to overwrite.`);\n process.exitCode = 1;\n return;\n }\n\n consola.success(`Wrote ${result.path}`);\n }\n});\n","import { defineCommand } from 'citty';\nimport { loadForgeMapConfig } from '../../config/load.ts';\n\nexport const configShowCommand = defineCommand({\n meta: {\n name: 'show',\n description: 'Print the resolved forgemap config and its source path'\n },\n args: {\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n process.stdout.write(\n JSON.stringify(\n {\n configFile: loaded.configFile ?? null,\n cwd: loaded.cwd,\n config: loaded.config\n },\n null,\n 2\n ) + '\\n'\n );\n }\n});\n","import { defineCommand } from 'citty';\nimport { configInitCommand } from './init.ts';\nimport { configShowCommand } from './show.ts';\n\nexport const configCommand = defineCommand({\n meta: {\n name: 'config',\n description: 'Manage the forgemap config file'\n },\n subCommands: {\n init: configInitCommand,\n show: configShowCommand\n }\n});\n","import { existsSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors } from 'consola/utils';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { removeCachedRepo } from '../repos/cache.ts';\nimport {\n classifyRemotes,\n evaluateRepo,\n localBlocker,\n localGateOverride,\n pruneEmptyDirs,\n remoteBlocker\n} from '../repos/evaluate.ts';\nimport { getUnpushedBranches } from '../repos/git.ts';\nimport type { ScannedRepo } from '../repos/scan.ts';\nimport { parseSlug } from '../slug/parse.ts';\nimport { resolveSlug } from '../slug/resolve.ts';\nimport { resolveRoot } from '../utils/path.ts';\n\nexport const deleteCommand = defineCommand({\n meta: {\n name: 'delete',\n description:\n 'Delete one local repo by slug, behind the same safety gates as cleanup (no staleness requirement)'\n },\n args: {\n slug: {\n type: 'positional',\n description: 'owner/repo, forge:owner/repo, or full URL',\n required: true\n },\n 'dry-run': {\n type: 'boolean',\n description: 'Only report what would happen; never prompt or delete',\n default: false\n },\n yes: {\n type: 'boolean',\n description: 'Skip the interactive confirmation (deletes immediately)',\n default: false\n },\n 'include-dirty': {\n type: 'boolean',\n description:\n 'Also delete when there are uncommitted changes (those changes are lost)',\n default: false\n },\n 'include-unpushed': {\n type: 'boolean',\n description:\n 'Also delete when there are unpushed commits (those commits are lost)',\n default: false\n },\n 'include-stashed': {\n type: 'boolean',\n description:\n 'Also delete when there is stashed work (that stash is lost)',\n default: false\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n\n // Resolve the slug straight to a path: `delete` targets one repo by name,\n // so it never scans (and therefore never writes the scan cache).\n let resolved: ReturnType<typeof resolveSlug>;\n try {\n resolved = resolveSlug(parseSlug(args.slug), {\n config: loaded.config,\n configDir\n });\n } catch (error) {\n consola.error((error as Error).message);\n process.exitCode = 1;\n return;\n }\n\n const repo: ScannedRepo = {\n forgeName: resolved.forgeName,\n forge: resolved.forge,\n owner: resolved.owner,\n repo: resolved.repo,\n localPath: resolved.localPath,\n slug: `${resolved.owner}/${resolved.repo}`\n };\n\n if (!existsSync(repo.localPath)) {\n consola.error(\n `No local repo at ${repo.localPath} — nothing to delete for ${repo.forgeName}:${repo.slug}.`\n );\n process.exitCode = 1;\n return;\n }\n\n // Not a git repo, or a git repo with no origin: forgemap cannot prove the\n // contents exist anywhere else, so it will not remove them.\n const evaluation = await evaluateRepo(repo);\n if (!evaluation) {\n consola.error(\n `Refusing to delete ${colors.cyan(`${repo.forgeName}:${repo.slug}`)} — ${repo.localPath} is not a git repo with an \"origin\" remote, so there is no remote copy to fall back on. Remove it by hand if you are sure.`\n );\n process.exitCode = 1;\n return;\n }\n\n process.stdout.write(\n `${colors.bold(`${repo.forgeName}:${repo.slug}`)} ${colors.dim(repo.localPath)}\\n`\n );\n\n // Name the local-only work rather than reporting a bare boolean, so the\n // user can see exactly what deleting this repo would destroy.\n const unpushedBranches = evaluation.unpushed\n ? await getUnpushedBranches(repo.localPath)\n : [];\n const losses: string[] = [];\n if (evaluation.dirty) losses.push('uncommitted changes');\n if (evaluation.unpushed) {\n losses.push(\n unpushedBranches.length > 0\n ? `unpushed commits on ${unpushedBranches.join(', ')}`\n : 'unpushed commits'\n );\n }\n if (evaluation.stashes > 0) {\n losses.push(\n `${evaluation.stashes} stash${evaluation.stashes === 1 ? '' : 'es'}`\n );\n }\n if (losses.length > 0) {\n process.stdout.write(\n ` ${colors.red('local-only work:')} ${losses.join('; ')}\\n`\n );\n }\n process.stdout.write('\\n');\n\n // A gone/unreachable remote is checked and reported first: it is the one\n // gate no flag can override, so nothing else about the repo matters.\n const remoteStates = await classifyRemotes([evaluation]);\n const remoteReason = remoteBlocker(remoteStates.get(repo.localPath)?.state);\n if (remoteReason) {\n consola.error(\n `Refusing to delete — ${remoteReason}. This is never overridable: the local copy may be the only one left.`\n );\n process.exitCode = 1;\n return;\n }\n\n const localReason = localBlocker(evaluation, {\n includeDirty: Boolean(args['include-dirty']),\n includeUnpushed: Boolean(args['include-unpushed']),\n includeStashed: Boolean(args['include-stashed'])\n });\n if (localReason) {\n const hint = localGateOverride(localReason);\n consola.error(\n `Refusing to delete — ${localReason}${hint ? `. Pass ${hint} to delete anyway (that work is lost)` : ''}.`\n );\n process.exitCode = 1;\n return;\n }\n\n if (args['dry-run']) {\n consola.info('Dry run — nothing deleted.');\n return;\n }\n\n if (losses.length > 0) {\n consola.warn(\n `This repo has local-only work that will be permanently lost: ${losses.join('; ')}.`\n );\n }\n\n // Deletion always requires the literal \"yes\"; --yes is the only bypass.\n let confirmed = args.yes;\n if (!confirmed) {\n const answer = await consola.prompt(\n `Type \"yes\" to delete ${repo.slug} locally:`,\n { type: 'text', cancel: 'null' }\n );\n confirmed = typeof answer === 'string' && answer.trim() === 'yes';\n }\n if (!confirmed) {\n consola.info('Aborted — nothing deleted.');\n return;\n }\n\n await rm(repo.localPath, { recursive: true, force: true });\n await removeCachedRepo(\n { config: loaded.config, configDir },\n repo.localPath\n );\n consola.success(`Deleted ${repo.localPath}`);\n\n const root = resolveRoot(loaded.config.root, configDir);\n const emptied = await pruneEmptyDirs(root, loaded.config);\n if (emptied > 0) {\n consola.success(`Removed ${emptied} empty folder(s).`);\n }\n }\n});\n","import type {\n ForgeConfig,\n ForgeType,\n GitForgeConfig,\n GitProtocol\n} from './schema.ts';\n\n/** Every forge `type` the config schema accepts, in prompt/display order. */\nexport const FORGE_TYPES: readonly ForgeType[] = [\n 'github',\n 'gitlab',\n 'gitea',\n 'codeberg',\n 'git'\n];\n\n/** Canonical host per forge type, offered as the host prompt's default. The\n * self-hosted flavors (`gitea`, plain `git`) have no universal host, so none\n * is suggested for them. */\nexport const DEFAULT_HOSTS: Partial<Record<ForgeType, string>> = {\n github: 'github.com',\n gitlab: 'gitlab.com',\n codeberg: 'codeberg.org'\n};\n\n/** Git clone protocols, in prompt order (`ssh` is the schema default). */\nexport const GIT_PROTOCOLS: readonly GitProtocol[] = ['ssh', 'https'];\n\nexport interface ForgeInput {\n type: ForgeType;\n host: string;\n dir: string;\n /** Only meaningful for `type: 'git'`. `ssh` is the schema default and is\n * dropped from the written config to keep it minimal — see {@link buildForge}. */\n protocol?: GitProtocol;\n}\n\n/**\n * A structurally-loose view of the config used by the in-place mutators below.\n * They run against both plain objects (the create path and unit tests) and\n * magicast proxies (round-trip writes), and the discriminated {@link ForgeConfig}\n * union is too strict to mutate field-by-field — so forges are treated as a flat\n * mutable record here.\n */\nexport interface MutableForge {\n type: ForgeType;\n host: string;\n dir: string;\n protocol?: GitProtocol;\n}\n\nexport interface EditableConfig {\n root?: string;\n defaultForge?: string;\n forges?: Record<string, MutableForge>;\n}\n\n/** Reject empty / whitespace-only keys; any other string is a valid map key.\n * Returns an error message, or `null` when the key is acceptable. */\nexport function validateForgeKey(raw: string): string | null {\n if (raw.trim().length === 0) return 'Forge key must not be empty.';\n return null;\n}\n\n/** Whether `value` is one of the schema's forge types (narrows a raw flag). */\nexport function isForgeType(value: string): value is ForgeType {\n return (FORGE_TYPES as readonly string[]).includes(value);\n}\n\n/** Whether `value` is a supported git protocol. */\nexport function isGitProtocol(value: string): value is GitProtocol {\n return (GIT_PROTOCOLS as readonly string[]).includes(value);\n}\n\n/** Build a `ForgeConfig` from collected input, keeping `protocol` only when it\n * is the non-default (`https`) git protocol. */\nexport function buildForge(input: ForgeInput): ForgeConfig {\n if (input.type === 'git') {\n const forge: GitForgeConfig = {\n type: 'git',\n host: input.host,\n dir: input.dir\n };\n if (input.protocol === 'https') forge.protocol = 'https';\n return forge;\n }\n // The non-git members are each just `BaseForgeConfig` with a fixed `type`; a\n // union-typed `type` field can't be expressed as an object literal, so assert\n // the shape (the `type` value is already narrowed to a non-git literal here).\n return { type: input.type, host: input.host, dir: input.dir } as ForgeConfig;\n}\n\nexport function addForge(\n config: EditableConfig,\n key: string,\n forge: MutableForge\n): void {\n if (!config.forges) config.forges = {};\n config.forges[key] = forge;\n}\n\nexport function removeForge(config: EditableConfig, key: string): void {\n if (config.forges) delete config.forges[key];\n}\n\nexport function setDefaultForge(config: EditableConfig, key: string): void {\n config.defaultForge = key;\n}\n\nexport interface ForgePatch {\n type?: ForgeType;\n host?: string;\n dir?: string;\n /** `null` clears the protocol; `undefined` leaves it untouched. */\n protocol?: GitProtocol | null;\n}\n\n/** Apply a partial change to an existing forge in place. Clears `protocol`\n * whenever the resulting type is not `git`, since it is meaningless there. */\nexport function editForge(\n config: EditableConfig,\n key: string,\n patch: ForgePatch\n): void {\n const forge = config.forges?.[key];\n if (!forge) return;\n if (patch.type !== undefined) forge.type = patch.type;\n if (patch.host !== undefined) forge.host = patch.host;\n if (patch.dir !== undefined) forge.dir = patch.dir;\n if (forge.type !== 'git') {\n delete forge.protocol;\n } else if (patch.protocol === null) {\n delete forge.protocol;\n } else if (patch.protocol !== undefined) {\n forge.protocol = patch.protocol;\n }\n}\n","import { readFile, writeFile } from 'node:fs/promises';\nimport { updateConfig } from 'c12/update';\nimport { dirname, extname } from 'pathe';\nimport type { EditableConfig } from './forges.ts';\n\n/**\n * Apply an in-place mutation to a `forgemap.config.*` file, preserving its\n * formatting and comments.\n *\n * `.ts`/`.mts`/`.js`/… are round-tripped through c12's `updateConfig`, which\n * parses the module with magicast and edits the exported object literal — it\n * transparently unwraps a `defineForgeMapConfig(...)` call. Plain `.json`\n * configs, which magicast/updateConfig refuse, are read, mutated and written\n * back directly.\n *\n * Rejects when the source can't be edited safely (e.g. forges built dynamically\n * rather than declared as a literal); callers surface that as a manual-edit\n * fallback rather than crashing.\n */\nexport async function mutateConfigFile(\n path: string,\n mutate: (config: EditableConfig) => void\n): Promise<void> {\n if (extname(path) === '.json') {\n const current = JSON.parse(await readFile(path, 'utf8')) as EditableConfig;\n mutate(current);\n await writeFile(path, `${JSON.stringify(current, null, 2)}\\n`, 'utf8');\n return;\n }\n // `updateConfig` resolves the config by base name from `cwd`; every forgemap\n // config is `forgemap.config.<ext>`, one per directory, so pointing `cwd` at\n // the target file's directory selects exactly that file.\n await updateConfig({\n cwd: dirname(path),\n configFile: 'forgemap.config',\n onUpdate: (config: EditableConfig) => {\n mutate(config);\n }\n });\n}\n","import consola from 'consola';\nimport { colors } from 'consola/utils';\nimport type { ScannedRepo } from './scan.ts';\n\n/**\n * Show the interactive repo picker and return the chosen local path\n * (undefined when the user cancels).\n *\n * `$(forgemap pick)` / `$(forgemap path <q>)` captures stdout, so the\n * interactive TUI must not go there. consola/clack writes the UI to stdout AND\n * reads stdout.rows/columns for layout — but a captured stdout is a pipe (no\n * rows → nothing renders). So for the duration of the prompt: route stdout\n * writes to stderr (the real TTY) and borrow stderr's dimensions, then\n * restore. stdout stays clean for the chosen path only.\n *\n * Callers must check {@link canPrompt} first — without a TTY on stdin there is\n * nobody to answer.\n */\nexport async function promptRepoChoice(\n candidates: ScannedRepo[]\n): Promise<string | undefined> {\n const out = process.stdout;\n const realWrite = out.write;\n const saved = {\n rows: Object.getOwnPropertyDescriptor(out, 'rows'),\n columns: Object.getOwnPropertyDescriptor(out, 'columns'),\n isTTY: Object.getOwnPropertyDescriptor(out, 'isTTY')\n };\n const fake = (key: 'rows' | 'columns' | 'isTTY', value: unknown) => {\n Object.defineProperty(out, key, { configurable: true, value });\n };\n const restore = (key: 'rows' | 'columns' | 'isTTY') => {\n if (saved[key]) Object.defineProperty(out, key, saved[key]!);\n else delete (out as unknown as Record<string, unknown>)[key];\n };\n\n out.write = process.stderr.write.bind(process.stderr) as typeof out.write;\n fake('rows', process.stderr.rows ?? 24);\n fake('columns', process.stderr.columns ?? 80);\n fake('isTTY', true);\n\n let choice: unknown;\n try {\n choice = await consola.prompt('Select a repo', {\n type: 'select',\n options: candidates.map((r) => ({\n label: `${colors.gray(`${r.forgeName}:`)}${r.slug}`,\n value: r.localPath,\n hint: r.localPath\n }))\n });\n } finally {\n out.write = realWrite;\n restore('rows');\n restore('columns');\n restore('isTTY');\n }\n\n return typeof choice === 'string' && choice ? choice : undefined;\n}\n\n/** Whether an interactive prompt can be shown at all. */\nexport function canPrompt(): boolean {\n return Boolean(process.stdin.isTTY);\n}\n","import { existsSync } from 'node:fs';\nimport consola from 'consola';\nimport { join, relative, resolve } from 'pathe';\nimport type { EditableConfig, MutableForge } from '../../config/forges.ts';\nimport type { LoadedConfig } from '../../config/load.ts';\nimport { discoverConfigFiles } from '../../config/load.ts';\nimport { mutateConfigFile } from '../../config/mutate.ts';\nimport { canPrompt } from '../../repos/picker.ts';\n\n/** Whether interactive prompts can be shown (a TTY on stdin to answer them). */\nexport function interactive(): boolean {\n return canPrompt();\n}\n\n/** Prompt for free text. Returns the raw string, or `null` when cancelled. */\nexport async function promptText(\n message: string,\n placeholder?: string\n): Promise<string | null> {\n const answer = await consola.prompt(message, {\n type: 'text',\n placeholder,\n cancel: 'null'\n });\n return typeof answer === 'string' ? answer : null;\n}\n\n/** Prompt to pick one of `options`. Returns the value, or `null` when cancelled. */\nexport async function promptSelect(\n message: string,\n options: readonly string[]\n): Promise<string | null> {\n const answer = await consola.prompt(message, {\n type: 'select',\n options: [...options],\n cancel: 'null'\n });\n return typeof answer === 'string' && answer ? answer : null;\n}\n\n/** Yes/no confirmation. Returns `false` when declined or cancelled. */\nexport async function confirmChange(message: string): Promise<boolean> {\n const answer = await consola.prompt(message, {\n type: 'confirm',\n cancel: 'null'\n });\n return answer === true;\n}\n\nexport interface TargetFile {\n path: string;\n /** The file does not exist yet and will be created (add only). */\n create: boolean;\n}\n\n/**\n * Choose which config file `add` writes to.\n * - `--config <path>` always wins (created when it does not exist).\n * - otherwise discover candidates: one → use it; several with a TTY → present a\n * select (the final step before confirming); several without a TTY → nearest.\n * - nothing discovered → a fresh `forgemap.config.ts` in the cwd.\n *\n * Returns `null` when the user cancels the select.\n */\nexport async function resolveAddTarget(\n explicit: string | undefined\n): Promise<TargetFile | null> {\n if (explicit) {\n const path = resolve(process.cwd(), explicit);\n return { path, create: !existsSync(path) };\n }\n const candidates = discoverConfigFiles();\n if (candidates.length === 0) {\n return { path: join(process.cwd(), 'forgemap.config.ts'), create: true };\n }\n if (candidates.length === 1 || !interactive()) {\n return { path: candidates[0]!.path, create: false };\n }\n const choice = await consola.prompt(\n 'Which config file should this change be written to?',\n {\n type: 'select',\n options: candidates.map((c) => ({\n label: relative(process.cwd(), c.path) || c.path,\n value: c.path,\n hint: c.source\n })),\n cancel: 'null'\n }\n );\n if (typeof choice !== 'string' || !choice) {\n consola.info('Aborted — nothing changed.');\n return null;\n }\n return { path: choice, create: false };\n}\n\n/**\n * The config file `edit`/`remove` operate on — the forge already lives in a real\n * file, so `--config` or the resolved config file is used. Prints an error and\n * returns `null` when only the built-in defaults are in effect (no file).\n */\nexport function existingConfigFile(\n loaded: LoadedConfig,\n explicit: string | undefined\n): string | null {\n if (explicit) return resolve(process.cwd(), explicit);\n if (!loaded.configFile) {\n consola.error(\n 'No forgemap config file found. Run `forgemap config init` or `forgemap forge add` first.'\n );\n return null;\n }\n return loaded.configFile;\n}\n\n/**\n * Round-trip `mutate` into `path`; on failure (a config too dynamic to rewrite)\n * report it and print the change for manual application instead of crashing.\n * Returns whether the file was updated.\n */\nexport async function applyChange(\n path: string,\n mutate: (config: EditableConfig) => void,\n manualHint: () => void\n): Promise<boolean> {\n try {\n await mutateConfigFile(path, mutate);\n return true;\n } catch (error) {\n consola.error(\n `Could not update ${path} automatically: ${(error as Error).message}`\n );\n consola.info('Apply this change by hand instead:');\n manualHint();\n return false;\n }\n}\n\n/** Print a forge as a `forgemap.config` block (the manual-edit fallback). */\nexport function printManualForge(key: string, forge: MutableForge): void {\n consola.log(` ${key}: {`);\n consola.log(` type: '${forge.type}',`);\n consola.log(` host: '${forge.host}',`);\n consola.log(` dir: '${forge.dir}'${forge.protocol ? ',' : ''}`);\n if (forge.protocol) consola.log(` protocol: '${forge.protocol}'`);\n consola.log(' }');\n}\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { dirname } from 'pathe';\nimport {\n DEFAULT_HOSTS,\n FORGE_TYPES,\n GIT_PROTOCOLS,\n addForge,\n buildForge,\n isForgeType,\n isGitProtocol,\n setDefaultForge,\n validateForgeKey\n} from '../../config/forges.ts';\nimport { loadForgeMapConfig } from '../../config/load.ts';\nimport type {\n ForgeMapConfig,\n ForgeType,\n GitProtocol\n} from '../../config/schema.ts';\nimport { writeConfigFile } from '../../config/write.ts';\nimport {\n applyChange,\n confirmChange,\n interactive,\n printManualForge,\n promptSelect,\n promptText,\n resolveAddTarget\n} from './shared.ts';\n\nexport const forgeAddCommand = defineCommand({\n meta: {\n name: 'add',\n description: 'Add a forge to the config (prompts for anything not passed)'\n },\n args: {\n key: {\n type: 'positional',\n required: false,\n description: 'Forge key, e.g. github or work'\n },\n type: {\n type: 'string',\n description: `Forge type (${FORGE_TYPES.join(', ')})`\n },\n host: { type: 'string', description: 'Forge host, e.g. github.com' },\n dir: {\n type: 'string',\n description: 'Directory under root, e.g. comGithub'\n },\n protocol: {\n type: 'string',\n description: `Clone protocol for type=git (${GIT_PROTOCOLS.join(', ')})`\n },\n default: {\n type: 'boolean',\n description: 'Set this forge as the default',\n default: false\n },\n config: {\n type: 'string',\n description: 'Path to the forgemap config file to modify'\n },\n yes: {\n type: 'boolean',\n description: 'Skip the confirmation prompt',\n default: false\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const tty = interactive();\n\n // ---- key ----\n let key = typeof args.key === 'string' ? args.key.trim() : '';\n if (!key && tty) {\n const answer = await promptText('Forge key (e.g. github, work):');\n if (answer === null) return abort();\n key = answer.trim();\n }\n const keyError = validateForgeKey(key);\n if (keyError) return fail(keyError);\n if (loaded.configFile && key in loaded.config.forges) {\n return fail(\n `Forge \"${key}\" already exists. Use \\`forgemap forge edit ${key}\\` to change it.`\n );\n }\n\n // ---- type ----\n let type: ForgeType | undefined;\n if (typeof args.type === 'string') {\n if (!isForgeType(args.type)) return fail(invalidType(args.type));\n type = args.type;\n } else if (tty) {\n const answer = await promptSelect('Forge type:', FORGE_TYPES);\n if (answer === null || !isForgeType(answer)) return abort();\n type = answer;\n }\n if (!type) return fail('Missing forge type. Pass --type.');\n\n // ---- host ----\n const suggestedHost = DEFAULT_HOSTS[type] ?? '';\n let host = typeof args.host === 'string' ? args.host.trim() : '';\n if (!host && tty) {\n const answer = await promptText('Host:', suggestedHost);\n if (answer === null) return abort();\n host = answer.trim() || suggestedHost;\n } else if (!host) {\n host = suggestedHost;\n }\n if (!host) return fail('Missing host. Pass --host.');\n\n // ---- dir ----\n let dir = typeof args.dir === 'string' ? args.dir.trim() : '';\n if (!dir && tty) {\n const answer = await promptText('Directory (under root):');\n if (answer === null) return abort();\n dir = answer.trim();\n }\n if (!dir) return fail('Missing directory. Pass --dir.');\n\n // ---- protocol (git only) ----\n let protocol: GitProtocol | undefined;\n if (type === 'git') {\n if (typeof args.protocol === 'string') {\n if (!isGitProtocol(args.protocol)) {\n return fail(invalidProtocol(args.protocol));\n }\n protocol = args.protocol;\n } else if (tty) {\n const answer = await promptSelect('Clone protocol:', GIT_PROTOCOLS);\n if (answer !== null && isGitProtocol(answer)) protocol = answer;\n }\n }\n\n // ---- default forge? ----\n // A brand-new config needs a default, so the first forge always becomes it.\n let makeDefault = args.default === true;\n if (!loaded.configFile) {\n makeDefault = true;\n } else if (!makeDefault && tty) {\n makeDefault = await confirmChange(`Set \"${key}\" as the default forge?`);\n }\n\n const forge = buildForge({ type, host, dir, protocol });\n\n // ---- target file (the final choice before applying) ----\n const target = await resolveAddTarget(args.config);\n if (!target) return;\n\n consola.info(\n `Add forge \"${key}\" (${type} → ${host}) into ${target.create ? 'new ' : ''}${target.path}`\n );\n if (tty && !args.yes && !(await confirmChange('Apply this change?'))) {\n return abort();\n }\n\n // ---- apply ----\n if (target.create) {\n const config: ForgeMapConfig = {\n root: loaded.config.root,\n defaultForge: key,\n forges: { [key]: forge }\n };\n const written = await writeConfigFile(config, {\n outDir: dirname(target.path)\n });\n if (!written) return fail(`${target.path} already exists.`);\n consola.success(`Added forge \"${key}\" — wrote ${written.path}`);\n return;\n }\n\n const applied = await applyChange(\n target.path,\n (c) => {\n addForge(c, key, forge);\n if (makeDefault) setDefaultForge(c, key);\n },\n () => printManualForge(key, forge)\n );\n if (applied) consola.success(`Added forge \"${key}\" to ${target.path}`);\n else process.exitCode = 1;\n }\n});\n\nfunction fail(message: string): void {\n consola.error(message);\n process.exitCode = 1;\n}\n\nfunction abort(): void {\n consola.info('Aborted — nothing changed.');\n}\n\nfunction invalidType(value: string): string {\n return `Invalid type \"${value}\". Expected one of: ${FORGE_TYPES.join(', ')}.`;\n}\n\nfunction invalidProtocol(value: string): string {\n return `Invalid protocol \"${value}\". Expected one of: ${GIT_PROTOCOLS.join(', ')}.`;\n}\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport {\n FORGE_TYPES,\n GIT_PROTOCOLS,\n type ForgePatch,\n type MutableForge,\n editForge,\n isForgeType,\n isGitProtocol\n} from '../../config/forges.ts';\nimport { loadForgeMapConfig } from '../../config/load.ts';\nimport type { ForgeType, GitProtocol } from '../../config/schema.ts';\nimport {\n applyChange,\n confirmChange,\n existingConfigFile,\n interactive,\n printManualForge,\n promptSelect,\n promptText\n} from './shared.ts';\n\nexport const forgeEditCommand = defineCommand({\n meta: {\n name: 'edit',\n description:\n 'Edit an existing forge (prompts for fields when none are passed)'\n },\n args: {\n key: {\n type: 'positional',\n required: false,\n description: 'Forge key to edit'\n },\n type: {\n type: 'string',\n description: `New forge type (${FORGE_TYPES.join(', ')})`\n },\n host: { type: 'string', description: 'New host' },\n dir: { type: 'string', description: 'New directory under root' },\n protocol: {\n type: 'string',\n description: `New clone protocol for type=git (${GIT_PROTOCOLS.join(', ')})`\n },\n config: {\n type: 'string',\n description: 'Path to the forgemap config file to modify'\n },\n yes: {\n type: 'boolean',\n description: 'Skip the confirmation prompt',\n default: false\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const tty = interactive();\n\n const file = existingConfigFile(loaded, args.config);\n if (!file) {\n process.exitCode = 1;\n return;\n }\n\n const forges = loaded.config.forges;\n\n // ---- which forge ----\n let key = typeof args.key === 'string' ? args.key.trim() : '';\n if (!key && tty) {\n const answer = await promptSelect(\n 'Which forge should be edited?',\n Object.keys(forges)\n );\n if (answer === null) return abort();\n key = answer;\n }\n if (!key) return fail('Missing forge key. Pass it as an argument.');\n const current = forges[key];\n if (!current) {\n return fail(\n `No forge \"${key}\" in ${file}. Configured: ${Object.keys(forges).join(', ')}.`\n );\n }\n const currentProtocol =\n current.type === 'git' ? current.protocol : undefined;\n\n const patch: ForgePatch = {};\n\n // ---- type ----\n if (typeof args.type === 'string') {\n if (!isForgeType(args.type)) return fail(invalidType(args.type));\n patch.type = args.type;\n } else if (tty) {\n const answer = await promptSelect(\n `Type (current: ${current.type}):`,\n FORGE_TYPES\n );\n if (answer === null) return abort();\n if (isForgeType(answer)) patch.type = answer;\n }\n const resultType: ForgeType = patch.type ?? current.type;\n\n // ---- host ----\n if (typeof args.host === 'string') {\n patch.host = args.host.trim();\n } else if (tty) {\n const answer = await promptText(\n `Host (current: ${current.host}):`,\n current.host\n );\n if (answer === null) return abort();\n if (answer.trim()) patch.host = answer.trim();\n }\n\n // ---- dir ----\n if (typeof args.dir === 'string') {\n patch.dir = args.dir.trim();\n } else if (tty) {\n const answer = await promptText(\n `Directory (current: ${current.dir}):`,\n current.dir\n );\n if (answer === null) return abort();\n if (answer.trim()) patch.dir = answer.trim();\n }\n\n // ---- protocol (only when the resulting type is git) ----\n if (resultType === 'git') {\n if (typeof args.protocol === 'string') {\n if (!isGitProtocol(args.protocol)) {\n return fail(invalidProtocol(args.protocol));\n }\n patch.protocol = args.protocol;\n } else if (tty) {\n const answer = await promptSelect('Clone protocol:', GIT_PROTOCOLS);\n if (answer !== null && isGitProtocol(answer)) patch.protocol = answer;\n }\n }\n\n if (!hasChanges(patch)) {\n return fail(\n 'Nothing to change. Pass --type, --host, --dir or --protocol.'\n );\n }\n\n consola.info(`Edit forge \"${key}\" in ${file}`);\n if (tty && !args.yes && !(await confirmChange('Apply this change?'))) {\n return abort();\n }\n\n const merged = mergeForge(current, currentProtocol, patch, resultType);\n const applied = await applyChange(\n file,\n (c) => editForge(c, key, patch),\n () => {\n consola.log(`Update the \"${key}\" entry to:`);\n printManualForge(key, merged);\n }\n );\n if (applied) consola.success(`Edited forge \"${key}\" in ${file}`);\n else process.exitCode = 1;\n }\n});\n\nfunction hasChanges(patch: ForgePatch): boolean {\n return (\n patch.type !== undefined ||\n patch.host !== undefined ||\n patch.dir !== undefined ||\n patch.protocol !== undefined\n );\n}\n\nfunction mergeForge(\n current: { type: ForgeType; host: string; dir: string },\n currentProtocol: GitProtocol | undefined,\n patch: ForgePatch,\n resultType: ForgeType\n): MutableForge {\n // `ForgePatch.protocol` can be null (editForge reads that as \"clear it\"), but\n // this command never sets it — a protocol only ever goes away by leaving git.\n const protocol =\n resultType === 'git' ? (patch.protocol ?? currentProtocol) : undefined;\n return {\n type: resultType,\n host: patch.host ?? current.host,\n dir: patch.dir ?? current.dir,\n ...(protocol ? { protocol } : {})\n };\n}\n\nfunction fail(message: string): void {\n consola.error(message);\n process.exitCode = 1;\n}\n\nfunction abort(): void {\n consola.info('Aborted — nothing changed.');\n}\n\nfunction invalidType(value: string): string {\n return `Invalid type \"${value}\". Expected one of: ${FORGE_TYPES.join(', ')}.`;\n}\n\nfunction invalidProtocol(value: string): string {\n return `Invalid protocol \"${value}\". Expected one of: ${GIT_PROTOCOLS.join(', ')}.`;\n}\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { removeForge, setDefaultForge } from '../../config/forges.ts';\nimport { loadForgeMapConfig } from '../../config/load.ts';\nimport {\n applyChange,\n confirmChange,\n existingConfigFile,\n interactive,\n promptSelect\n} from './shared.ts';\n\nconst LEAVE_UNSET = '— leave unset —';\n\nexport const forgeRemoveCommand = defineCommand({\n meta: {\n name: 'remove',\n description: 'Remove a forge from the config'\n },\n args: {\n key: {\n type: 'positional',\n required: false,\n description: 'Forge key to remove'\n },\n default: {\n type: 'string',\n description:\n 'When removing the default forge, reassign the default to this'\n },\n config: {\n type: 'string',\n description: 'Path to the forgemap config file to modify'\n },\n yes: {\n type: 'boolean',\n description: 'Skip the confirmation prompt',\n default: false\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const tty = interactive();\n\n const file = existingConfigFile(loaded, args.config);\n if (!file) {\n process.exitCode = 1;\n return;\n }\n\n const forges = loaded.config.forges;\n\n // ---- which forge ----\n let key = typeof args.key === 'string' ? args.key.trim() : '';\n if (!key && tty) {\n const answer = await promptSelect(\n 'Which forge should be removed?',\n Object.keys(forges)\n );\n if (answer === null) return abort();\n key = answer;\n }\n if (!key) return fail('Missing forge key. Pass it as an argument.');\n if (!(key in forges)) {\n return fail(\n `No forge \"${key}\" in ${file}. Configured: ${Object.keys(forges).join(', ')}.`\n );\n }\n\n // ---- reassign the default when it is the one being removed ----\n const remaining = Object.keys(forges).filter((k) => k !== key);\n let newDefault: string | undefined;\n if (loaded.config.defaultForge === key && remaining.length > 0) {\n if (typeof args.default === 'string') {\n if (!remaining.includes(args.default)) {\n return fail(\n `Cannot set default to \"${args.default}\" — not a remaining forge (${remaining.join(', ')}).`\n );\n }\n newDefault = args.default;\n } else if (tty) {\n const answer = await promptSelect(\n `\"${key}\" is the default forge. Pick a new default:`,\n [...remaining, LEAVE_UNSET]\n );\n if (answer === null) return abort();\n if (answer !== LEAVE_UNSET) newDefault = answer;\n } else {\n consola.warn(\n `Removing the default forge \"${key}\"; defaultForge now points at a missing forge. Pass --default to reassign it.`\n );\n }\n }\n\n consola.info(\n `Remove forge \"${key}\" from ${file}${newDefault ? ` (new default: \"${newDefault}\")` : ''}`\n );\n if (tty && !args.yes && !(await confirmChange('Apply this change?'))) {\n return abort();\n }\n\n const applied = await applyChange(\n file,\n (c) => {\n removeForge(c, key);\n if (newDefault) setDefaultForge(c, newDefault);\n },\n () => consola.log(`Remove the \"${key}\" entry from \\`forges\\` in ${file}.`)\n );\n if (applied) consola.success(`Removed forge \"${key}\" from ${file}`);\n else process.exitCode = 1;\n }\n});\n\nfunction fail(message: string): void {\n consola.error(message);\n process.exitCode = 1;\n}\n\nfunction abort(): void {\n consola.info('Aborted — nothing changed.');\n}\n","import { defineCommand } from 'citty';\nimport { forgeAddCommand } from './add.ts';\nimport { forgeEditCommand } from './edit.ts';\nimport { forgeRemoveCommand } from './remove.ts';\n\nexport const forgeCommand = defineCommand({\n meta: {\n name: 'forge',\n description: 'Add, remove or edit forges in the config'\n },\n subCommands: {\n add: forgeAddCommand,\n remove: forgeRemoveCommand,\n edit: forgeEditCommand\n }\n});\n","import { readdir } from 'node:fs/promises';\nimport { join } from 'pathe';\nimport type {\n ForgeConfig,\n ForgeMapConfig,\n ForgeType\n} from '../config/schema.ts';\nimport { getForgeAdapter } from '../forges/registry.ts';\nimport type { RemoteCheckInput, RemoteCheckResult } from '../forges/types.ts';\nimport { mapLimit } from '../utils/concurrency.ts';\nimport { parseSlug } from '../slug/parse.ts';\nimport { getOriginUrl, getRemotes, isGitRepo, type GitRemote } from './git.ts';\n\n/** Layout kinds importable today. `forgemap` = the `<server>/<owner>/<repo>`\n * tree forgemap itself manages. Kept as an enum to extend later. */\nexport type ImportType = 'forgemap';\n\nexport interface ImportOptions {\n /** Absolute path to scan (already expanded/resolved). */\n path: string;\n type: ImportType;\n /** Run the per-forge network existence/move check. Default true. */\n remoteCheck: boolean;\n /** Called as remote checks complete, for progress reporting. */\n onProgress?: (done: number, total: number) => void;\n}\n\nexport interface DiscoveredRepo {\n serverDir: string;\n owner: string;\n repo: string;\n localPath: string;\n}\n\nexport type FindingKind =\n | 'not-a-git-repo'\n | 'no-origin'\n | 'multiple-remotes'\n | 'origin-mismatch'\n | 'remote-moved'\n | 'remote-gone'\n | 'host-unmatched'\n | 'remote-check-skipped'\n | 'remote-check-unknown';\n\nexport type FindingSeverity = 'ok' | 'warn' | 'fail';\n\nexport type Fix =\n | { action: 'move-folder'; from: string; to: string }\n | { action: 'set-origin-url'; localPath: string; url: string };\n\nexport interface Finding {\n kind: FindingKind;\n severity: FindingSeverity;\n message: string;\n fix?: Fix;\n}\n\nexport interface RepoReport {\n repo: DiscoveredRepo;\n originUrl: string | null;\n /** Host parsed from the origin URL, when parseable. Drives config derivation. */\n originHost: string | null;\n remotes: GitRemote[];\n findings: Finding[];\n}\n\nexport interface DerivedConfig extends ForgeMapConfig {}\n\nexport interface ImportResult {\n root: string;\n derived: DerivedConfig;\n reports: RepoReport[];\n}\n\nasync function listDirs(path: string): Promise<string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => e.name);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw error;\n }\n}\n\n/**\n * Structure-driven depth-3 walk of `<path>/<serverDir>/<owner>/<repo>`.\n * Unlike `scanRepos`, this is config-free: every top-level directory is a\n * candidate server dir, and the names are discovered rather than configured.\n */\nexport async function discoverForgemapLayout(\n path: string\n): Promise<DiscoveredRepo[]> {\n const repos: DiscoveredRepo[] = [];\n for (const serverDir of await listDirs(path)) {\n const serverPath = join(path, serverDir);\n for (const owner of await listDirs(serverPath)) {\n const ownerPath = join(serverPath, owner);\n for (const repo of await listDirs(ownerPath)) {\n repos.push({\n serverDir,\n owner,\n repo,\n localPath: join(ownerPath, repo)\n });\n }\n }\n }\n return repos;\n}\n\nfunction forgeTypeForHost(host: string): ForgeType {\n return host === 'github.com' ? 'github' : 'git';\n}\n\n/**\n * Derive a `root` + one forge per server dir from the analyzed reports.\n * Host (and therefore type) come from the dominant origin host of the repos\n * under each server dir.\n */\nexport function deriveConfig(\n reports: RepoReport[],\n path: string\n): DerivedConfig {\n const forges: Record<string, ForgeConfig> = {};\n const counts = new Map<string, number>();\n\n const byServer = new Map<string, RepoReport[]>();\n for (const report of reports) {\n const list = byServer.get(report.repo.serverDir);\n if (list) list.push(report);\n else byServer.set(report.repo.serverDir, [report]);\n }\n\n for (const [serverDir, group] of byServer) {\n counts.set(serverDir, group.length);\n const hostTally = new Map<string, number>();\n for (const report of group) {\n if (report.originHost) {\n hostTally.set(\n report.originHost,\n (hostTally.get(report.originHost) ?? 0) + 1\n );\n }\n }\n const host =\n [...hostTally.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? '';\n const type = host ? forgeTypeForHost(host) : 'git';\n forges[serverDir] = { type, host, dir: serverDir } as ForgeConfig;\n }\n\n // Prefer a github forge, then the one with the most repos.\n const names = Object.keys(forges);\n const defaultForge =\n names.slice().sort((a, b) => {\n const aGh = forges[a]!.type === 'github' ? 1 : 0;\n const bGh = forges[b]!.type === 'github' ? 1 : 0;\n if (aGh !== bGh) return bGh - aGh;\n return (counts.get(b) ?? 0) - (counts.get(a) ?? 0);\n })[0] ?? '';\n\n return { root: path, defaultForge, forges };\n}\n\n/** Parsed origin identity carried between the local and remote phases. */\ninterface ParsedOrigin {\n host?: string;\n owner: string;\n repo: string;\n}\n\n/** Local phase: git reads + offline folder-vs-origin reconciliation. No network. */\nasync function analyzeLocal(\n repo: DiscoveredRepo,\n options: ImportOptions\n): Promise<{ report: RepoReport; parsed: ParsedOrigin | null }> {\n const report: RepoReport = {\n repo,\n originUrl: null,\n originHost: null,\n remotes: [],\n findings: []\n };\n\n if (!(await isGitRepo(repo.localPath))) {\n report.findings.push({\n kind: 'not-a-git-repo',\n severity: 'warn',\n message: 'not a git repository'\n });\n return { report, parsed: null };\n }\n\n report.remotes = await getRemotes(repo.localPath);\n report.originUrl = await getOriginUrl(repo.localPath);\n\n if (!report.originUrl) {\n const names = report.remotes\n .map((r) => r.name)\n .filter((n) => n !== 'origin');\n report.findings.push({\n kind: 'no-origin',\n severity: 'warn',\n message:\n names.length > 0\n ? `no origin remote (other remotes: ${names.join(', ')})`\n : 'no origin remote'\n });\n return { report, parsed: null };\n }\n\n if (report.remotes.length > 1) {\n report.findings.push({\n kind: 'multiple-remotes',\n severity: 'warn',\n message: `${report.remotes.length} remotes configured; comparing origin`\n });\n }\n\n let parsed: ParsedOrigin | null = null;\n try {\n parsed = parseSlug(report.originUrl);\n report.originHost = parsed.host ?? null;\n } catch {\n report.findings.push({\n kind: 'origin-mismatch',\n severity: 'warn',\n message: `could not parse origin URL: ${report.originUrl}`\n });\n }\n\n if (parsed && (parsed.owner !== repo.owner || parsed.repo !== repo.repo)) {\n const to = join(options.path, repo.serverDir, parsed.owner, parsed.repo);\n report.findings.push({\n kind: 'origin-mismatch',\n severity: 'warn',\n message: `folder ${repo.owner}/${repo.repo} != origin ${parsed.owner}/${parsed.repo}`,\n fix: { action: 'move-folder', from: repo.localPath, to }\n });\n }\n\n return { report, parsed };\n}\n\n/** Translate a remote-check result into a finding on the report. */\nfunction pushRemoteFinding(\n report: RepoReport,\n parsed: ParsedOrigin,\n result: RemoteCheckResult,\n path: string\n): void {\n const { repo } = report;\n switch (result.state) {\n case 'exists':\n break;\n case 'moved': {\n const to = join(\n path,\n repo.serverDir,\n result.canonical.owner,\n result.canonical.repo\n );\n const fix: Fix | undefined = result.canonicalUrl\n ? {\n action: 'set-origin-url',\n localPath: repo.localPath,\n url: result.canonicalUrl\n }\n : to !== repo.localPath\n ? { action: 'move-folder', from: repo.localPath, to }\n : undefined;\n report.findings.push({\n kind: 'remote-moved',\n severity: 'warn',\n message: `remote moved to ${result.canonical.owner}/${result.canonical.repo}`,\n fix\n });\n break;\n }\n case 'gone':\n report.findings.push({\n kind: 'remote-gone',\n severity: 'warn',\n message: `remote ${parsed.owner}/${parsed.repo} no longer exists`\n });\n break;\n case 'unknown':\n report.findings.push({\n kind: 'remote-check-unknown',\n severity: 'warn',\n message: `remote check inconclusive: ${result.reason}`\n });\n break;\n }\n}\n\n/** A repo that has a parseable origin and is therefore eligible for the\n * network check, paired with its derived forge. */\ninterface Checkable {\n report: RepoReport;\n parsed: ParsedOrigin;\n}\n\n/** Run the network check for one forge's repos, preferring the batched\n * adapter method and falling back to a concurrency-limited per-repo loop. */\nasync function checkForgeGroup(\n forge: ForgeConfig,\n items: Checkable[],\n options: ImportOptions,\n bump: () => void\n): Promise<void> {\n const inputs: RemoteCheckInput[] = items.map((it) => ({\n forge,\n owner: it.parsed.owner,\n repo: it.parsed.repo,\n originUrl: it.report.originUrl ?? undefined\n }));\n\n let adapter: ReturnType<typeof getForgeAdapter>;\n try {\n adapter = getForgeAdapter(forge.type);\n } catch (error) {\n for (const it of items) {\n it.report.findings.push({\n kind: 'remote-check-unknown',\n severity: 'warn',\n message: `remote check inconclusive: ${(error as Error).message}`\n });\n bump();\n }\n return;\n }\n\n if (adapter.checkRemotes) {\n let results: RemoteCheckResult[];\n try {\n results = await adapter.checkRemotes(inputs);\n } catch (error) {\n results = inputs.map(() => ({\n state: 'unknown',\n reason: (error as Error).message\n }));\n }\n items.forEach((it, i) => {\n pushRemoteFinding(it.report, it.parsed, results[i]!, options.path);\n bump();\n });\n return;\n }\n\n const check = adapter.checkRemote;\n await mapLimit(items, REMOTE_CONCURRENCY, async (it, i) => {\n let result: RemoteCheckResult;\n try {\n result = check\n ? await check(inputs[i]!)\n : { state: 'unknown', reason: `${forge.type} has no remote check` };\n } catch (error) {\n result = { state: 'unknown', reason: (error as Error).message };\n }\n pushRemoteFinding(it.report, it.parsed, result, options.path);\n bump();\n });\n}\n\nconst LOCAL_CONCURRENCY = 16;\nconst REMOTE_CONCURRENCY = 10;\n\n/** Discover, reconcile, and (optionally) network-check an importable tree. */\nexport async function analyzeImport(\n options: ImportOptions\n): Promise<ImportResult> {\n const discovered = await discoverForgemapLayout(options.path);\n\n const locals = await mapLimit(discovered, LOCAL_CONCURRENCY, (repo) =>\n analyzeLocal(repo, options)\n );\n const reports = locals.map((l) => l.report);\n const derived = deriveConfig(reports, options.path);\n\n // host-unmatched is offline but needs the derived forge to compare against.\n for (const { report, parsed } of locals) {\n const forge = derived.forges[report.repo.serverDir];\n if (parsed?.host && forge?.host && parsed.host !== forge.host) {\n report.findings.push({\n kind: 'host-unmatched',\n severity: 'warn',\n message: `origin host ${parsed.host} differs from forge host ${forge.host}`\n });\n }\n }\n\n const checkable: Checkable[] = locals.flatMap((l) =>\n l.report.originUrl && l.parsed\n ? [{ report: l.report, parsed: l.parsed }]\n : []\n );\n\n if (!options.remoteCheck) {\n for (const { report } of checkable) {\n report.findings.push({\n kind: 'remote-check-skipped',\n severity: 'ok',\n message: 'remote check skipped (--no-remote-check)'\n });\n }\n return { root: options.path, derived, reports };\n }\n\n const total = checkable.length;\n let done = 0;\n const bump = () => {\n done++;\n options.onProgress?.(done, total);\n };\n options.onProgress?.(0, total);\n\n // Group by server dir so each forge's repos can be checked in one batch.\n const groups = new Map<string, Checkable[]>();\n for (const item of checkable) {\n const key = item.report.repo.serverDir;\n const list = groups.get(key);\n if (list) list.push(item);\n else groups.set(key, [item]);\n }\n\n await Promise.all(\n Array.from(groups, ([serverDir, items]) => {\n const forge = derived.forges[serverDir];\n if (!forge) {\n for (const it of items) {\n it.report.findings.push({\n kind: 'remote-check-unknown',\n severity: 'warn',\n message: 'no forge derived for this server dir'\n });\n bump();\n }\n return Promise.resolve();\n }\n return checkForgeGroup(forge, items, options, bump);\n })\n );\n\n return { root: options.path, derived, reports };\n}\n","import { existsSync } from 'node:fs';\nimport { mkdir, rename, stat } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors, formatTree } from 'consola/utils';\nimport { dirname, join, resolve } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport type { ForgeConfig, ForgeMapConfig } from '../config/schema.ts';\nimport { writeConfigFile } from '../config/write.ts';\nimport { scanReposCached } from '../repos/cache.ts';\nimport { setOriginUrl } from '../repos/git.ts';\nimport {\n analyzeImport,\n type Finding,\n type FindingSeverity,\n type Fix,\n type ImportType,\n type RepoReport\n} from '../repos/import.ts';\n\nconst ALLOWED_TYPES: ImportType[] = ['forgemap'];\nconst ALLOWED_FORMATS = ['pretty', 'json'];\n\nfunction isImportType(value: string): value is ImportType {\n return (ALLOWED_TYPES as string[]).includes(value);\n}\n\nfunction severitySymbol(severity: FindingSeverity): string {\n if (severity === 'fail') return colors.red('✗');\n if (severity === 'warn') return colors.yellow('!');\n return colors.green('✓');\n}\n\nfunction worstSeverity(findings: Finding[]): FindingSeverity {\n if (findings.some((f) => f.severity === 'fail')) return 'fail';\n if (findings.some((f) => f.severity === 'warn')) return 'warn';\n return 'ok';\n}\n\nfunction hasIssues(report: RepoReport): boolean {\n return report.findings.some((f) => f.severity !== 'ok');\n}\n\nfunction repoLine(report: RepoReport): string {\n const symbol = severitySymbol(worstSeverity(report.findings));\n const name = colors.cyan(report.repo.repo);\n const issues = report.findings.filter((f) => f.severity !== 'ok');\n if (issues.length === 0) return `${symbol} ${name}`;\n const summary = issues.map((f) => f.message).join('; ');\n return `${symbol} ${name} ${colors.dim(summary)}`;\n}\n\n// Three levels, like a path: serverDir → owner → repo.\nfunction renderReports(reports: RepoReport[]): string {\n const byServer = new Map<string, Map<string, RepoReport[]>>();\n for (const report of reports) {\n let owners = byServer.get(report.repo.serverDir);\n if (!owners) {\n owners = new Map();\n byServer.set(report.repo.serverDir, owners);\n }\n const list = owners.get(report.repo.owner);\n if (list) list.push(report);\n else owners.set(report.repo.owner, [report]);\n }\n return formatTree(\n Array.from(byServer, ([serverDir, owners]) => ({\n text: colors.bold(serverDir),\n children: Array.from(owners, ([owner, items]) => ({\n text: owner,\n children: items.map((report) => ({ text: repoLine(report) }))\n }))\n }))\n );\n}\n\nfunction renderDerived(config: ForgeMapConfig): string {\n return formatTree([\n {\n text: colors.bold('Derived config'),\n children: Object.entries(config.forges).map(([name, forge]) => ({\n text: `${colors.cyan(name)} ${colors.dim(\n `${forge.type} @ ${forge.host || '(unknown host)'} → ${forge.dir}`\n )}`\n }))\n }\n ]);\n}\n\nasync function applyFixes(reports: RepoReport[]): Promise<Fix[]> {\n const applied: Fix[] = [];\n const fixes = reports.flatMap((r) =>\n r.findings.flatMap((f) => (f.fix ? [f.fix] : []))\n );\n\n // Repoint URLs first so a repo's git config is corrected before it moves.\n for (const fix of fixes) {\n if (fix.action !== 'set-origin-url') continue;\n const result = await setOriginUrl(fix.localPath, fix.url);\n if (result.code === 0) {\n applied.push(fix);\n consola.success(`origin → ${fix.url}`);\n } else {\n consola.warn(\n `failed to set origin for ${fix.localPath}: ${result.stderr.trim()}`\n );\n }\n }\n\n for (const fix of fixes) {\n if (fix.action !== 'move-folder') continue;\n if (existsSync(fix.to)) {\n consola.warn(`skip move: target exists ${fix.to}`);\n continue;\n }\n await mkdir(dirname(fix.to), { recursive: true });\n await rename(fix.from, fix.to);\n applied.push(fix);\n consola.success(`moved ${fix.from} → ${fix.to}`);\n }\n\n return applied;\n}\n\n/** Merge derived forges into an existing config without clobbering existing\n * keys. Returns the merged config plus any conflicting keys. */\nfunction augmentConfig(\n existing: ForgeMapConfig,\n derived: ForgeMapConfig\n): { merged: ForgeMapConfig; conflicts: string[] } {\n const forges: Record<string, ForgeConfig> = { ...existing.forges };\n const conflicts: string[] = [];\n for (const [name, forge] of Object.entries(derived.forges)) {\n const current = existing.forges[name];\n if (!current) {\n forges[name] = forge;\n } else if (current.host !== forge.host) {\n conflicts.push(name);\n }\n }\n return { merged: { ...existing, forges }, conflicts };\n}\n\nexport const importCommand = defineCommand({\n meta: {\n name: 'import',\n description:\n 'Adopt an existing repo tree: reconcile folders against git remotes and derive a config'\n },\n args: {\n path: {\n type: 'positional',\n description: 'Directory laid out as <server>/<owner>/<repo>',\n required: true\n },\n type: {\n type: 'string',\n description: 'Layout type (currently only \"forgemap\")',\n default: 'forgemap'\n },\n format: {\n type: 'string',\n description: 'Output format: pretty (default) or json',\n default: 'pretty'\n },\n 'remote-check': {\n type: 'boolean',\n description: 'Check each remote for existence/moves (default true)',\n default: true\n },\n fix: {\n type: 'boolean',\n description: 'Apply corrections (move folders, repoint origin URLs)',\n default: false\n },\n 'write-config': {\n type: 'boolean',\n description:\n 'Write/augment forgemap.config.ts from the derived structure',\n default: true\n },\n out: {\n type: 'string',\n description:\n 'Directory to write the derived config into (defaults to <path>)'\n },\n force: {\n type: 'boolean',\n description: 'Overwrite an existing config instead of augmenting it',\n default: false\n }\n },\n async run({ args }) {\n if (!isImportType(args.type)) {\n consola.error(\n `Invalid --type value \"${args.type}\". Allowed: ${ALLOWED_TYPES.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n if (!ALLOWED_FORMATS.includes(args.format)) {\n consola.error(\n `Invalid --format value \"${args.format}\". Allowed: ${ALLOWED_FORMATS.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n\n const path = resolve(process.cwd(), args.path);\n try {\n const s = await stat(path);\n if (!s.isDirectory()) {\n consola.error(`${path} is not a directory.`);\n process.exitCode = 1;\n return;\n }\n } catch {\n consola.error(`${path} does not exist.`);\n process.exitCode = 1;\n return;\n }\n\n // Progress for the (potentially slow) remote checks. stderr-only and\n // TTY-guarded so it never corrupts JSON on stdout or piped logs.\n const showProgress = args['remote-check'] && Boolean(process.stderr.isTTY);\n let clearLen = 0;\n const onProgress = showProgress\n ? (done: number, total: number) => {\n const msg = `⏳ Checking remotes ${done}/${total}`;\n process.stderr.write(`\\r${msg} `);\n clearLen = msg.length + 1;\n }\n : undefined;\n\n const result = await analyzeImport({\n path,\n type: args.type,\n remoteCheck: args['remote-check'],\n onProgress\n });\n\n if (clearLen > 0) {\n process.stderr.write(`\\r${' '.repeat(clearLen)}\\r`);\n }\n\n const applied = args.fix ? await applyFixes(result.reports) : [];\n\n const withFindings = result.reports.filter(hasIssues).length;\n const fixable = result.reports.reduce(\n (n, r) => n + r.findings.filter((f) => f.fix).length,\n 0\n );\n\n if (args.format === 'json') {\n process.stdout.write(\n `${JSON.stringify(\n {\n path,\n type: args.type,\n derived: result.derived,\n repos: result.reports.map((r) => ({\n serverDir: r.repo.serverDir,\n owner: r.repo.owner,\n repo: r.repo.repo,\n localPath: r.repo.localPath,\n originUrl: r.originUrl,\n remotes: r.remotes,\n findings: r.findings\n })),\n ...(args.fix ? { applied } : {}),\n summary: { repos: result.reports.length, withFindings, fixable }\n },\n null,\n 2\n )}\\n`\n );\n } else {\n process.stdout.write(\n `${colors.dim(`Scanned ${path} (${args.type})`)}\\n\\n`\n );\n if (result.reports.length === 0) {\n consola.info('No repos found.');\n } else {\n process.stdout.write(`${renderReports(result.reports)}\\n\\n`);\n }\n process.stdout.write(`${renderDerived(result.derived)}\\n\\n`);\n process.stdout.write(\n `${colors.bold(`${result.reports.length} repos`)}, ${withFindings} with findings, ${fixable} fixable${\n args.fix ? `, ${applied.length} fixed` : ''\n }\\n`\n );\n }\n\n if (!args['write-config']) return;\n if (result.reports.length === 0 && !args.force) return;\n\n const outDir = args.out ? resolve(process.cwd(), args.out) : path;\n const writableRoot = outDir === path ? '.' : path;\n const target = join(outDir, 'forgemap.config.ts');\n\n if (existsSync(target) && !args.force) {\n const loaded = await loadForgeMapConfig({ configFile: target });\n const { merged, conflicts } = augmentConfig(\n loaded.config,\n result.derived\n );\n for (const name of conflicts) {\n consola.warn(\n `forge \"${name}\" already exists with a different host — left untouched`\n );\n }\n await writeConfigFile(merged, { outDir, force: true });\n consola.success(`Augmented ${target}`);\n } else {\n const written = await writeConfigFile(\n { ...result.derived, root: writableRoot },\n { outDir, force: args.force }\n );\n if (written) consola.success(`Wrote ${written.path}`);\n }\n\n // Warm the scan cache so the next status/list hits the hot path.\n await scanReposCached({\n config: result.derived,\n configDir: path,\n useCache: false\n });\n }\n});\n","import { existsSync, readFileSync, realpathSync } from 'node:fs';\nimport { defineCommand } from 'citty';\nimport { colors } from 'consola/utils';\nimport { dirname, join, resolve } from 'pathe';\nimport { type ConfigSource, loadForgeMapConfig } from '../config/load.ts';\nimport { resolveRoot } from '../utils/path.ts';\n\n// Injected at build time by vite's `define` (see vite.config.ts), sourced from\n// package.json's `version`. Read it the same way `cli.ts` does rather than\n// re-inventing a drift-prone literal.\ndeclare const __APP_VERSION__: string;\n\n/** `linked` = runs from a git work tree; `release` = an installed package. */\ntype BuildKind = 'linked' | 'release' | 'unknown';\n\ninterface BuildInfo {\n kind: BuildKind;\n /** Directory of the nearest `forgemap` package.json above the binary. */\n packageRoot: string | null;\n reason: string;\n}\n\ninterface BinaryInfo {\n /** The path as invoked (may be a shim / symlink). */\n invoked: string | null;\n /** The real executed file, symlinks resolved. */\n resolved: string | null;\n}\n\ninterface ForgeInfo {\n name: string;\n type: string;\n dir: string;\n}\n\ninterface ConfigInfo {\n source: ConfigSource | 'error';\n file: string | null;\n root: string | null;\n forges: ForgeInfo[];\n /** Set when the config could not be loaded (missing/broken); else null. */\n error: string | null;\n}\n\ninterface Info {\n version: string;\n build: BuildInfo;\n binary: BinaryInfo;\n node: string;\n config: ConfigInfo;\n}\n\n/** Resolve the real executed file behind any shim or symlink. */\nfunction resolveBinary(entry: string | undefined): BinaryInfo {\n if (!entry) return { invoked: null, resolved: null };\n try {\n return { invoked: entry, resolved: realpathSync(entry) };\n } catch {\n // The file vanished (or is unreadable) — report the invoked path as-is\n // rather than failing; `info` describes, it never judges.\n return { invoked: entry, resolved: entry };\n }\n}\n\n/** Walk up from `start` to the nearest package.json, returning its dir + name. */\nfunction findPackageRoot(\n start: string\n): { dir: string; name: string | undefined } | null {\n let dir = resolve(start);\n for (;;) {\n const pkgPath = join(dir, 'package.json');\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as {\n name?: string;\n };\n return { dir, name: pkg.name };\n } catch {\n return { dir, name: undefined };\n }\n }\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\n/**\n * Distinguish a linked/dev build from an installed release: the resolved binary\n * lives inside a git work tree whose package.json is named `forgemap`. An\n * installed package has the same package.json but no `.git` beside it. When the\n * binary or a `forgemap` package.json cannot be located, report `unknown`\n * rather than guessing.\n */\nfunction detectBuild(resolved: string | null): BuildInfo {\n if (!resolved) {\n return {\n kind: 'unknown',\n packageRoot: null,\n reason: 'binary path could not be resolved'\n };\n }\n const pkg = findPackageRoot(dirname(resolved));\n if (!pkg) {\n return {\n kind: 'unknown',\n packageRoot: null,\n reason: 'no package.json found above the binary'\n };\n }\n if (pkg.name !== 'forgemap') {\n return {\n kind: 'unknown',\n packageRoot: pkg.dir,\n reason: `nearest package.json is \"${pkg.name ?? 'unnamed'}\", not forgemap`\n };\n }\n // Check `.git` only at the forgemap package root, never above it: an installed\n // package under a consumer's node_modules would otherwise inherit that repo's\n // .git and be mislabelled as linked.\n const inGitTree = existsSync(join(pkg.dir, '.git'));\n return {\n kind: inGitTree ? 'linked' : 'release',\n packageRoot: pkg.dir,\n reason: inGitTree\n ? 'runs from a git work tree named forgemap'\n : 'installed forgemap package (no git work tree beside it)'\n };\n}\n\nasync function gatherConfig(\n configFile: string | undefined\n): Promise<ConfigInfo> {\n try {\n const loaded = await loadForgeMapConfig({ configFile });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n return {\n source: loaded.source,\n file: loaded.configFile ?? null,\n root: resolveRoot(loaded.config.root, configDir),\n forges: Object.entries(loaded.config.forges).map(([name, forge]) => ({\n name,\n type: forge.type,\n dir: forge.dir\n })),\n error: null\n };\n } catch (error) {\n // A broken config file must not sink the whole command — the config is one\n // section of the output, not a prerequisite for version/paths/node.\n return {\n source: 'error',\n file: null,\n root: null,\n forges: [],\n error: (error as Error).message\n };\n }\n}\n\nconst SOURCE_LABELS: Record<ConfigSource | 'error', string> = {\n flag: '--config flag',\n env: 'FORGEMAP_CONFIG env',\n 'walk-up': 'walk-up from cwd',\n global: 'global ($XDG_CONFIG_HOME/forgemap)',\n default: 'built-in defaults (no config file found)',\n error: 'failed to load'\n};\n\nconst BUILD_LABELS: Record<BuildKind, string> = {\n linked: 'linked / dev build',\n release: 'installed release',\n unknown: 'unknown'\n};\n\nfunction row(label: string, value: string): string {\n return ` ${colors.dim(label.padEnd(9))} ${value}\\n`;\n}\n\nfunction renderPretty(info: Info): string {\n let out = `${colors.bold('forgemap')} ${colors.cyan(`v${info.version}`)} ${colors.dim(`(${BUILD_LABELS[info.build.kind]})`)}\\n`;\n out += row('build', colors.dim(info.build.reason));\n out += row('binary', info.binary.resolved ?? colors.dim('unknown'));\n if (info.binary.invoked && info.binary.invoked !== info.binary.resolved) {\n out += row('', colors.dim(`via ${info.binary.invoked}`));\n }\n out += row('node', info.node);\n\n out += `\\n${colors.bold('config')}\\n`;\n out += row('source', SOURCE_LABELS[info.config.source]);\n if (info.config.error) {\n out += row('error', colors.red(info.config.error));\n } else {\n out += row('file', info.config.file ?? colors.dim('none'));\n out += row('root', info.config.root ?? colors.dim('unknown'));\n }\n\n out += `\\n${colors.bold('forges')}\\n`;\n if (info.config.forges.length === 0) {\n out += ` ${colors.dim('none')}\\n`;\n } else {\n for (const forge of info.config.forges) {\n out += ` ${colors.cyan(forge.name.padEnd(12))} ${forge.type} ${colors.dim('→')} ${forge.dir}\\n`;\n }\n }\n return out;\n}\n\nexport const infoCommand = defineCommand({\n meta: {\n name: 'info',\n description:\n 'Describe this installation: version, binary path, node, and resolved config'\n },\n args: {\n json: {\n type: 'boolean',\n description: 'Emit a machine-readable JSON report',\n default: false\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const binary = resolveBinary(process.argv[1]);\n const info: Info = {\n version: __APP_VERSION__,\n build: detectBuild(binary.resolved),\n binary,\n node: process.version,\n config: await gatherConfig(args.config)\n };\n\n if (args.json) {\n process.stdout.write(`${JSON.stringify(info, null, 2)}\\n`);\n return;\n }\n process.stdout.write(renderPretty(info));\n }\n});\n\nexport const __test = { resolveBinary, findPackageRoot, detectBuild };\n","import type { ScannedRepo } from './scan.ts';\n\nconst FLAG = '--filter';\n\n/**\n * Shared `--filter` option for the commands that enumerate repos\n * (`status`, `sync`, `list`), so the flag reads identically everywhere.\n */\nexport const filterArg = {\n type: 'string',\n description:\n 'Restrict to repos whose owner or forge name matches. Repeatable; a repo passes if it matches any value.'\n} as const;\n\n/**\n * Recover every `--filter` occurrence from the raw argv.\n *\n * citty (0.2.2) parses through `node:util` `parseArgs` and never sets\n * `multiple: true`, so Node keeps only the **last** value of a repeated option:\n * `--filter a --filter b` reaches `args.filter` as `'b'`, silently dropping\n * `a`. The raw argv is the only place the full list survives.\n */\nexport function collectFilterArgs(rawArgs: string[]): string[] {\n const values: string[] = [];\n for (let i = 0; i < rawArgs.length; i++) {\n const arg = rawArgs[i]!;\n // Everything past `--` is positional, not ours to read.\n if (arg === '--') break;\n if (arg === FLAG) {\n const next = rawArgs[i + 1];\n // A bare trailing `--filter`, or `--filter --json`, has no value.\n if (next !== undefined && !next.startsWith('-')) {\n values.push(next);\n i++;\n }\n continue;\n }\n if (arg.startsWith(`${FLAG}=`)) values.push(arg.slice(FLAG.length + 1));\n }\n return values;\n}\n\n/**\n * Normalize the shapes a filter value arrives in — absent, a single string, or\n * a list — into a list, dropping blanks (`--filter ''`).\n */\nexport function normalizeFilters(\n value: string | string[] | undefined\n): string[] {\n if (value === undefined) return [];\n const values = Array.isArray(value) ? value : [value];\n return values.map((v) => v.trim()).filter((v) => v.length > 0);\n}\n\n/**\n * The filter values for a run: the raw argv wins, since it is the only shape\n * that survives repetition. Fall back to the parsed value when the argv carries\n * no `--filter` at all, which is how the command is driven programmatically\n * (and in tests), where `rawArgs` may be empty.\n */\nexport function resolveFilters(\n rawArgs: string[],\n value: string | string[] | undefined\n): string[] {\n const fromRawArgs = collectFilterArgs(rawArgs);\n return normalizeFilters(fromRawArgs.length > 0 ? fromRawArgs : value);\n}\n\n/**\n * Keep the repos matching any of `filters` (OR-combined). A value matches when\n * it equals the repo's owner or its forge name, compared case-insensitively —\n * forge and owner names are case-preserving but not case-significant. An empty\n * filter list is a no-op, so an unused flag never narrows the output.\n */\nexport function filterRepos(\n repos: ScannedRepo[],\n filters: string[]\n): ScannedRepo[] {\n if (filters.length === 0) return repos;\n const wanted = new Set(filters.map((f) => f.toLowerCase()));\n return repos.filter(\n (r) =>\n wanted.has(r.owner.toLowerCase()) || wanted.has(r.forgeName.toLowerCase())\n );\n}\n","import Fuse, { type IFuseOptions } from 'fuse.js';\nimport type { ScannedRepo } from './scan.ts';\n\n/**\n * The one Fuse configuration every fuzzy lookup shares — `list`, `pick`\n * and the fuzzy slug fallback in `path`/`open`. Keeping it in one place is\n * what makes a query rank identically no matter which command runs it.\n */\nexport const REPO_FUSE_OPTIONS: IFuseOptions<ScannedRepo> = {\n keys: ['slug', 'owner', 'repo'],\n threshold: 0.3,\n ignoreLocation: true\n};\n\nexport function createRepoFuse(repos: ScannedRepo[]): Fuse<ScannedRepo> {\n return new Fuse(repos, REPO_FUSE_OPTIONS);\n}\n\n/** Fuzzy-match `query` against scanned repos, best match first. */\nexport function matchRepos(\n repos: ScannedRepo[],\n query: string,\n limit?: number\n): ScannedRepo[] {\n const fuse = createRepoFuse(repos);\n const results = fuse.search(query, limit ? { limit } : undefined);\n return results.map((r) => r.item);\n}\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors, formatTree } from 'consola/utils';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { filterArg, filterRepos, resolveFilters } from '../repos/filter.ts';\nimport { matchRepos } from '../repos/match.ts';\nimport { type ScannedRepo, scanRepos } from '../repos/scan.ts';\n\ntype Format = 'auto' | 'pretty' | 'path' | 'slug';\n\n// Three levels, like a path: forge → owner → repo.\nfunction renderTree(repos: ScannedRepo[]): string {\n const byForge = new Map<string, Map<string, ScannedRepo[]>>();\n for (const r of repos) {\n let owners = byForge.get(r.forgeName);\n if (!owners) {\n owners = new Map();\n byForge.set(r.forgeName, owners);\n }\n const list = owners.get(r.owner);\n if (list) list.push(r);\n else owners.set(r.owner, [r]);\n }\n\n return formatTree(\n Array.from(byForge, ([forge, owners]) => ({\n text: colors.bold(forge),\n children: Array.from(owners, ([owner, items]) => ({\n text: owner,\n children: items.map((r) => ({\n text: `${colors.cyan(r.repo)} ${colors.dim(r.localPath)}`\n }))\n }))\n }))\n );\n}\n\nexport const listCommand = defineCommand({\n meta: {\n name: 'list',\n description:\n 'List cloned repos; with a query, fuzzy-match by owner/repo and print matches'\n },\n args: {\n query: {\n type: 'positional',\n description:\n 'Optional search term (matched fuzzily against <owner>/<repo>). Omit to list every repo.',\n required: false\n },\n format: {\n type: 'string',\n description:\n 'Output format: auto (default), pretty, path, or slug. auto picks pretty in a TTY, path when piped.',\n default: 'auto'\n },\n filter: filterArg,\n limit: {\n type: 'string',\n description: 'Maximum number of matches to print (default: unlimited)'\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args, rawArgs }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const scanned = await scanRepos({ config: loaded.config, configDir });\n // Narrow before matching, so --limit counts matches within the filtered set.\n const repos = filterRepos(scanned, resolveFilters(rawArgs, args.filter));\n\n const limit = args.limit ? Number.parseInt(args.limit, 10) : undefined;\n // No query lists everything: Fuse treats an empty query as \"match all\".\n const query = args.query ?? '';\n const items = matchRepos(repos, query, limit);\n\n const allowed: Format[] = ['auto', 'pretty', 'path', 'slug'];\n if (!allowed.includes(args.format as Format)) {\n consola.error(\n `Invalid --format value \"${args.format}\". Allowed: ${allowed.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n const requested = args.format as Format;\n const format: Exclude<Format, 'auto'> =\n requested === 'auto'\n ? process.stdout.isTTY\n ? 'pretty'\n : 'path'\n : requested;\n\n if (items.length === 0) {\n if (format === 'pretty') {\n consola.info(query ? `No matches for \"${query}\".` : 'No repos found.');\n }\n return;\n }\n\n if (format === 'pretty') {\n process.stdout.write(`${renderTree(items)}\\n`);\n return;\n }\n\n for (const item of items) {\n process.stdout.write(\n `${format === 'slug' ? item.slug : item.localPath}\\n`\n );\n }\n }\n});\n","import consola from 'consola';\nimport { colors } from 'consola/utils';\nimport type { ForgeMapConfig } from '../config/schema.ts';\nimport { matchRepos } from '../repos/match.ts';\nimport { canPrompt, promptRepoChoice } from '../repos/picker.ts';\nimport { type ScannedRepo, scanRepos } from '../repos/scan.ts';\nimport { looksLikeSlug, parseSlug } from './parse.ts';\nimport { resolveSlug } from './resolve.ts';\n\nexport interface LocateOptions {\n config: ForgeMapConfig;\n configDir: string;\n /** Pre-scanned repos. Scanned on demand when omitted. */\n repos?: ScannedRepo[];\n}\n\nexport type LocateOutcome =\n /** Input was a strict slug — resolved by layout, cloned or not. */\n | { kind: 'slug'; localPath: string }\n /** Fuzzy query hit exactly one cloned repo. */\n | { kind: 'match'; localPath: string; repo: ScannedRepo }\n /** Fuzzy query hit several cloned repos. */\n | { kind: 'ambiguous'; query: string; candidates: ScannedRepo[] }\n /** Fuzzy query hit nothing. */\n | { kind: 'none'; query: string };\n\n/**\n * Turn user input into a repo location.\n *\n * A strict slug is resolved from the configured layout and never consults the\n * disk — so an explicit `owner/repo` always wins over any fuzzy match, and\n * still resolves for a repo that isn't cloned yet. Only input that cannot be a\n * slug at all falls back to fuzzy-matching the cloned repos.\n *\n * Throws for malformed *slugs* (`foo/bar/baz`, a bad URL, empty input) — those\n * are mistakes to report, not queries to guess at.\n */\nexport async function locateRepo(\n input: string,\n options: LocateOptions\n): Promise<LocateOutcome> {\n const { config, configDir } = options;\n\n if (!input.trim() || looksLikeSlug(input)) {\n const resolved = resolveSlug(parseSlug(input), { config, configDir });\n return { kind: 'slug', localPath: resolved.localPath };\n }\n\n const repos = options.repos ?? (await scanRepos({ config, configDir }));\n const candidates = matchRepos(repos, input);\n\n if (candidates.length === 0) return { kind: 'none', query: input };\n if (candidates.length === 1) {\n return {\n kind: 'match',\n localPath: candidates[0]!.localPath,\n repo: candidates[0]!\n };\n }\n return { kind: 'ambiguous', query: input, candidates };\n}\n\n/**\n * {@link locateRepo} plus the interactive/diagnostic layer shared by `path`\n * and `open`: prompt on an ambiguous query when there is a TTY to prompt on,\n * otherwise explain and fail. Returns null when nothing was resolved — the\n * caller sets the exit code.\n *\n * Every diagnostic goes to stderr: `$(forgemap path <q>)` captures stdout, and\n * a hint leaking into that capture would be read as a path.\n */\nexport async function resolveRepoPath(\n input: string,\n options: LocateOptions\n): Promise<string | null> {\n const outcome = await locateRepo(input, options);\n\n switch (outcome.kind) {\n case 'slug':\n case 'match':\n return outcome.localPath;\n\n case 'none':\n consola.error(`No cloned repo matches \"${outcome.query}\".`);\n process.stderr.write(\n `${colors.dim('Pass an explicit <owner>/<repo> for a repo that is not cloned yet.')}\\n`\n );\n return null;\n\n case 'ambiguous': {\n if (canPrompt()) {\n return (await promptRepoChoice(outcome.candidates)) ?? null;\n }\n consola.error(\n `\"${outcome.query}\" matches ${outcome.candidates.length} cloned repos:`\n );\n for (const c of outcome.candidates) {\n process.stderr.write(\n ` ${colors.cyan(`${c.forgeName}:${c.slug}`)} ${colors.dim(c.localPath)}\\n`\n );\n }\n process.stderr.write(\n `${colors.dim('Narrow the query, pass an explicit <owner>/<repo>, or run `forgemap pick` to choose interactively.')}\\n`\n );\n return null;\n }\n }\n}\n","import { spawn } from 'node:child_process';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { resolveRepoPath } from '../slug/locate.ts';\n\ninterface OpenInvocation {\n cmd: string;\n args: string[];\n}\n\nfunction platformOpen(localPath: string): OpenInvocation {\n const distro = process.env.WSL_DISTRO_NAME;\n if (distro) {\n const winPath = `\\\\\\\\wsl$\\\\${distro}${localPath.replaceAll('/', '\\\\')}`;\n return { cmd: 'explorer.exe', args: [winPath] };\n }\n if (process.platform === 'darwin') {\n return { cmd: 'open', args: [localPath] };\n }\n return { cmd: 'xdg-open', args: [localPath] };\n}\n\nexport const openCommand = defineCommand({\n meta: {\n name: 'open',\n description:\n 'Open a repo in the OS file manager (Explorer on WSL, Finder on macOS, xdg-open elsewhere)'\n },\n args: {\n slug: {\n type: 'positional',\n description:\n 'owner/repo, forge:owner/repo, full URL, or a fuzzy query matched against cloned repos',\n required: true\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const localPath = await resolveRepoPath(args.slug, {\n config: loaded.config,\n configDir\n });\n if (!localPath) {\n process.exitCode = 1;\n return;\n }\n\n const { cmd, args: cmdArgs } = platformOpen(localPath);\n consola.info(`Opening ${localPath}`);\n\n const child = spawn(cmd, cmdArgs, {\n stdio: 'ignore',\n detached: true\n });\n child.on('error', (error: NodeJS.ErrnoException) => {\n if (error.code === 'ENOENT') {\n consola.error(\n `Could not find \\`${cmd}\\`. Install it (or open the path manually).`\n );\n process.exitCode = 1;\n } else {\n consola.error(error.message);\n process.exitCode = 1;\n }\n });\n child.unref();\n }\n});\n","import { defineCommand } from 'citty';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { resolveRepoPath } from '../slug/locate.ts';\n\nexport const pathCommand = defineCommand({\n meta: {\n name: 'path',\n description: 'Print the local path where a repo lives (or would live)'\n },\n args: {\n slug: {\n type: 'positional',\n description:\n 'owner/repo, forge:owner/repo, full URL, or a fuzzy query matched against cloned repos',\n required: true\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const localPath = await resolveRepoPath(args.slug, {\n config: loaded.config,\n configDir\n });\n if (!localPath) {\n process.exitCode = 1;\n return;\n }\n process.stdout.write(`${localPath}\\n`);\n }\n});\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { matchRepos } from '../repos/match.ts';\nimport { canPrompt, promptRepoChoice } from '../repos/picker.ts';\nimport { type ScannedRepo, scanRepos } from '../repos/scan.ts';\n\nexport const pickCommand = defineCommand({\n meta: {\n name: 'pick',\n description:\n 'Interactively pick a cloned repo from the configured layout and print its path'\n },\n args: {\n query: {\n type: 'positional',\n description: 'Optional fuzzy filter applied before showing the picker',\n required: false\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const all = await scanRepos({ config: loaded.config, configDir });\n\n const candidates: ScannedRepo[] = args.query\n ? matchRepos(all, args.query)\n : all;\n\n if (candidates.length === 0) {\n consola.error(\n args.query\n ? `No repos match \"${args.query}\".`\n : 'No repos found under the configured root.'\n );\n process.exitCode = 1;\n return;\n }\n\n if (candidates.length === 1) {\n process.stdout.write(`${candidates[0]!.localPath}\\n`);\n return;\n }\n\n if (!canPrompt()) {\n consola.error(\n 'pick requires an interactive terminal. Use `forgemap list` for non-interactive output.'\n );\n process.exitCode = 1;\n return;\n }\n\n const choice = await promptRepoChoice(candidates);\n if (choice) {\n process.stdout.write(`${choice}\\n`);\n }\n }\n});\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport {\n type Shell,\n SUPPORTED_SHELLS as SUPPORTED,\n detectShell,\n installRcBlock\n} from '../utils/shell.ts';\n\n/** Append (idempotently) a loader that, plus completion, sets up the shell so\n * the user only has to re-source their rc file. */\nasync function install(shell: Shell, name: string): Promise<void> {\n const nameArg = name && name !== 'forgemap' ? ` --name ${name}` : '';\n const loaders =\n shell === 'fish'\n ? [\n `forgemap shell-init fish${nameArg} | source`,\n 'forgemap completion fish | source'\n ]\n : [\n `eval \"$(forgemap shell-init ${shell}${nameArg})\"`,\n `eval \"$(forgemap completion ${shell})\"`\n ];\n // 'shell-init' is the legacy label (before this block also loaded\n // completion) — strip it so a re-install never leaves a duplicate.\n const { status, rcFile } = await installRcBlock(shell, 'shell', loaders, [\n 'shell-init'\n ]);\n if (status === 'present') {\n consola.info(`forgemap shell integration already present in ${rcFile}.`);\n return;\n }\n const verb = status === 'updated' ? 'Updated' : 'Added';\n consola.success(\n `${verb} forgemap shell integration (cd + completion) in ${rcFile}.`\n );\n consola.info(\n `Run \\`source ${rcFile}\\` or restart your shell to activate it.`\n );\n}\n\nfunction renderPosix(name: string): string {\n return `# forgemap shell integration — drop into your ~/.zshrc / ~/.bashrc:\n# eval \"$(forgemap shell-init)\"\n#\n# Wraps the forgemap binary so that \\`${name} cd <slug>\\` actually changes\n# directory in this shell. All other subcommands fall through unchanged.\n\n${name}() {\n if [ \"$1\" = \"cd\" ]; then\n shift\n local target\n if [ \"$#\" -eq 0 ]; then\n target=$(command forgemap pick) || return $?\n else\n local matches\n matches=$(command forgemap list \"$1\" --format path)\n local count\n count=$(printf '%s' \"$matches\" | grep -c '^/' || true)\n if [ \"$count\" = \"1\" ]; then\n target=\"$matches\"\n elif [ \"$count\" = \"0\" ]; then\n echo \"forgemap cd: no match for $1\" >&2\n return 1\n else\n target=$(command forgemap pick \"$1\") || return $?\n fi\n fi\n [ -n \"$target\" ] && builtin cd \"$target\"\n return\n fi\n command forgemap \"$@\"\n}\n`;\n}\n\nfunction renderFish(name: string): string {\n return `# forgemap shell integration — drop into your ~/.config/fish/config.fish:\n# forgemap shell-init fish | source\n\nfunction ${name} --description \"forgemap with cd interception\"\n if test (count $argv) -ge 1 -a \"$argv[1]\" = \"cd\"\n set --erase argv[1]\n set target \"\"\n if test (count $argv) -eq 0\n set target (command forgemap pick); or return $status\n else\n set matches (command forgemap list $argv[1] --format path)\n set count (count $matches)\n if test $count -eq 1\n set target $matches[1]\n else if test $count -eq 0\n echo \"forgemap cd: no match for $argv[1]\" >&2\n return 1\n else\n set target (command forgemap pick $argv[1]); or return $status\n end\n end\n test -n \"$target\"; and builtin cd $target\n return\n end\n command forgemap $argv\nend\n`;\n}\n\nexport const shellInitCommand = defineCommand({\n meta: {\n name: 'shell-init',\n description:\n 'Print (or --install) a shell wrapper that adds `forgemap cd <slug>` as a real cd. Source it via `eval \"$(forgemap shell-init)\"`.'\n },\n args: {\n shell: {\n type: 'positional',\n description: `Shell flavor (${SUPPORTED.join(', ')}). Auto-detected from $SHELL if omitted.`,\n required: false\n },\n name: {\n type: 'string',\n description: 'Name of the generated wrapper function (default: forgemap)',\n default: 'forgemap'\n },\n install: {\n type: 'boolean',\n description:\n \"Append the loader to your shell's rc file (idempotent) instead of printing\",\n default: false\n }\n },\n async run({ args }) {\n const requested = (args.shell ?? detectShell()) as Shell;\n if (!SUPPORTED.includes(requested)) {\n consola.error(\n `Unsupported shell \"${requested}\". Supported: ${SUPPORTED.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n const name = args.name || 'forgemap';\n if (args.install) {\n await install(requested, name);\n return;\n }\n const out = requested === 'fish' ? renderFish(name) : renderPosix(name);\n process.stdout.write(out);\n }\n});\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors, formatTree } from 'consola/utils';\nimport Fuse from 'fuse.js';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { scanReposCached } from '../repos/cache.ts';\nimport { filterArg, filterRepos, resolveFilters } from '../repos/filter.ts';\nimport { getRepoStatus, type RepoStatus } from '../repos/git.ts';\nimport type { ScannedRepo } from '../repos/scan.ts';\n\ninterface Row {\n repo: ScannedRepo;\n status: RepoStatus | null;\n error?: string;\n}\n\nfunction statusLine(row: Row): string {\n if (row.error || !row.status) {\n return `${colors.cyan(row.repo.repo)} ${colors.red(`error: ${row.error ?? 'unknown'}`)}`;\n }\n const s = row.status;\n const parts: string[] = [colors.cyan(row.repo.repo)];\n const aheadBehind: string[] = [];\n if (s.ahead > 0) aheadBehind.push(colors.green(`↑${s.ahead}`));\n if (s.behind > 0) aheadBehind.push(colors.yellow(`↓${s.behind}`));\n if (aheadBehind.length > 0) parts.push(aheadBehind.join(' '));\n parts.push(s.dirty ? colors.red('●') : colors.green('✓'));\n // Stashed work is invisible to every other marker here — surface it before\n // it matters (e.g. before `cleanup` considers the repo).\n if (s.stashes > 0) parts.push(colors.yellow(`⚑${s.stashes}`));\n parts.push(colors.gray(s.branch));\n if (s.lastCommit) {\n parts.push(colors.dim(`${s.lastCommit.sha} ${s.lastCommit.relativeDate}`));\n }\n return parts.join(' ');\n}\n\n// Three levels, like a path: forge → owner → repo.\nfunction renderTree(rows: Row[]): string {\n const byForge = new Map<string, Map<string, Row[]>>();\n for (const row of rows) {\n let owners = byForge.get(row.repo.forgeName);\n if (!owners) {\n owners = new Map();\n byForge.set(row.repo.forgeName, owners);\n }\n const list = owners.get(row.repo.owner);\n if (list) list.push(row);\n else owners.set(row.repo.owner, [row]);\n }\n return formatTree(\n Array.from(byForge, ([forge, owners]) => ({\n text: colors.bold(forge),\n children: Array.from(owners, ([owner, items]) => ({\n text: owner,\n children: items.map((row) => ({ text: statusLine(row) }))\n }))\n }))\n );\n}\n\nconst ALLOWED_FORMATS = ['pretty', 'json'];\n\nexport const statusCommand = defineCommand({\n meta: {\n name: 'status',\n description: 'Show branch, dirty, ahead/behind, and last commit per repo'\n },\n args: {\n format: {\n type: 'string',\n description: 'Output format: pretty (default) or json',\n default: 'pretty'\n },\n forge: {\n type: 'string',\n description: 'Restrict to a single forge alias'\n },\n filter: filterArg,\n query: {\n type: 'string',\n description: 'Fuzzy filter against <owner>/<repo>'\n },\n cache: {\n type: 'boolean',\n description: 'Use the scanned-repos cache',\n negativeDescription: 'Skip the scanned-repos cache',\n default: true\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args, rawArgs }) {\n if (!ALLOWED_FORMATS.includes(args.format)) {\n consola.error(\n `Invalid --format value \"${args.format}\". Allowed: ${ALLOWED_FORMATS.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n let repos = await scanReposCached({\n config: loaded.config,\n configDir,\n useCache: args.cache\n });\n\n if (args.forge) {\n repos = repos.filter((r) => r.forgeName === args.forge);\n }\n repos = filterRepos(repos, resolveFilters(rawArgs, args.filter));\n if (args.query) {\n const fuse = new Fuse(repos, {\n keys: ['slug', 'owner', 'repo'],\n threshold: 0.3,\n ignoreLocation: true\n });\n repos = fuse.search(args.query).map((r) => r.item);\n }\n\n const rows: Row[] = await Promise.all(\n repos.map(async (repo) => {\n try {\n return { repo, status: await getRepoStatus(repo.localPath) };\n } catch (error) {\n return { repo, status: null, error: (error as Error).message };\n }\n })\n );\n\n if (args.format === 'json') {\n process.stdout.write(\n `${JSON.stringify(\n rows.map((r) => ({\n forge: r.repo.forgeName,\n owner: r.repo.owner,\n repo: r.repo.repo,\n localPath: r.repo.localPath,\n status: r.status,\n error: r.error ?? null\n })),\n null,\n 2\n )}\\n`\n );\n return;\n }\n\n if (rows.length === 0) {\n consola.info('No repos to report on.');\n return;\n }\n process.stdout.write(`${renderTree(rows)}\\n`);\n }\n});\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors } from 'consola/utils';\nimport Fuse from 'fuse.js';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { scanReposCached } from '../repos/cache.ts';\nimport { filterArg, filterRepos, resolveFilters } from '../repos/filter.ts';\nimport { fetchRepo, isClean, pullRepo } from '../repos/git.ts';\nimport type { ScannedRepo } from '../repos/scan.ts';\n\ninterface SyncOutcome {\n repo: ScannedRepo;\n status: 'synced' | 'skipped' | 'failed';\n message?: string;\n}\n\nasync function runWithConcurrency<T>(\n items: T[],\n limit: number,\n task: (item: T) => Promise<void>\n): Promise<void> {\n const queue = [...items];\n const workers = Array.from(\n { length: Math.min(limit, queue.length) },\n async () => {\n while (queue.length > 0) {\n const next = queue.shift();\n if (!next) return;\n await task(next);\n }\n }\n );\n await Promise.all(workers);\n}\n\nexport const syncCommand = defineCommand({\n meta: {\n name: 'sync',\n description:\n 'Run git fetch (or --pull) across every cloned repo, in parallel'\n },\n args: {\n pull: {\n type: 'boolean',\n description:\n 'Pull --ff-only instead of fetch. Dirty working trees are skipped.',\n default: false\n },\n concurrency: {\n type: 'string',\n description: 'Number of parallel workers (default: 4)'\n },\n sequential: {\n type: 'boolean',\n description: 'Run one repo at a time (overrides --concurrency)',\n default: false\n },\n forge: {\n type: 'string',\n description: 'Restrict to a single forge alias'\n },\n filter: filterArg,\n query: {\n type: 'string',\n description: 'Fuzzy filter against <owner>/<repo>'\n },\n cache: {\n type: 'boolean',\n description: 'Use the scanned-repos cache',\n negativeDescription: 'Skip the scanned-repos cache',\n default: true\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args, rawArgs }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n let repos = await scanReposCached({\n config: loaded.config,\n configDir,\n useCache: args.cache\n });\n\n if (args.forge) {\n repos = repos.filter((r) => r.forgeName === args.forge);\n }\n repos = filterRepos(repos, resolveFilters(rawArgs, args.filter));\n if (args.query) {\n const fuse = new Fuse(repos, {\n keys: ['slug', 'owner', 'repo'],\n threshold: 0.3,\n ignoreLocation: true\n });\n repos = fuse.search(args.query).map((r) => r.item);\n }\n\n if (repos.length === 0) {\n consola.info('Nothing to sync.');\n return;\n }\n\n const concurrency = args.sequential\n ? 1\n : args.concurrency\n ? Math.max(1, Number.parseInt(args.concurrency, 10))\n : 4;\n\n consola.info(\n `Syncing ${repos.length} repo(s) — ${args.pull ? 'pull' : 'fetch'}, concurrency ${concurrency}`\n );\n\n const outcomes: SyncOutcome[] = [];\n await runWithConcurrency(repos, concurrency, async (repo) => {\n try {\n if (args.pull && !(await isClean(repo.localPath))) {\n outcomes.push({\n repo,\n status: 'skipped',\n message: 'dirty working tree'\n });\n consola.warn(`${colors.dim(repo.slug)} — skipped (dirty)`);\n return;\n }\n const result = args.pull\n ? await pullRepo(repo.localPath)\n : await fetchRepo(repo.localPath);\n if (result.code === 0) {\n outcomes.push({ repo, status: 'synced' });\n consola.success(colors.dim(repo.slug));\n } else {\n const message = result.timedOut\n ? 'timed out (remote unreachable)'\n : (result.stderr || result.stdout).trim().split('\\n')[0] ||\n `git exited with code ${result.code}`;\n outcomes.push({\n repo,\n status: 'failed',\n message\n });\n consola.fail(\n `${colors.dim(repo.slug)} — ${outcomes.at(-1)?.message}`\n );\n }\n } catch (error) {\n outcomes.push({\n repo,\n status: 'failed',\n message: (error as Error).message\n });\n consola.fail(`${colors.dim(repo.slug)} — ${(error as Error).message}`);\n }\n });\n\n const synced = outcomes.filter((o) => o.status === 'synced').length;\n const skipped = outcomes.filter((o) => o.status === 'skipped').length;\n const failed = outcomes.filter((o) => o.status === 'failed').length;\n consola.info(\n `Done — ${colors.green(`${synced} synced`)}, ${colors.yellow(`${skipped} skipped`)}, ${colors.red(`${failed} failed`)}`\n );\n if (failed > 0) {\n process.exitCode = 1;\n }\n }\n});\n","import { access } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors } from 'consola/utils';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport type { ForgeConfig, ForgeMapConfig } from '../config/schema.ts';\nimport { resolveRoot } from '../utils/path.ts';\nimport { execCapture, hasCommand } from '../utils/exec.ts';\n\ntype CheckSeverity = 'ok' | 'warn' | 'fail';\n\ninterface Check {\n name: string;\n severity: CheckSeverity;\n message: string;\n}\n\nconst KNOWN_TYPES = new Set(['github', 'gitlab', 'gitea', 'codeberg', 'git']);\n\nfunction validateForge(name: string, forge: ForgeConfig): Check {\n if (!KNOWN_TYPES.has(forge.type)) {\n return {\n name: `forge \"${name}\"`,\n severity: 'fail',\n message: `unknown type \"${forge.type}\"`\n };\n }\n if (!forge.host?.trim()) {\n return {\n name: `forge \"${name}\"`,\n severity: 'fail',\n message: 'host is empty'\n };\n }\n if (!forge.dir?.trim()) {\n return {\n name: `forge \"${name}\"`,\n severity: 'fail',\n message: 'dir is empty'\n };\n }\n return {\n name: `forge \"${name}\"`,\n severity: 'ok',\n message: `${forge.type} at ${forge.host}`\n };\n}\n\nasync function runChecks(\n config: ForgeMapConfig,\n configDir: string\n): Promise<Check[]> {\n const checks: Check[] = [];\n\n for (const [name, forge] of Object.entries(config.forges)) {\n checks.push(validateForge(name, forge));\n }\n\n checks.push(\n config.forges[config.defaultForge]\n ? {\n name: 'defaultForge',\n severity: 'ok',\n message: `→ ${config.defaultForge}`\n }\n : {\n name: 'defaultForge',\n severity: 'fail',\n message: `\"${config.defaultForge}\" is not in forges`\n }\n );\n\n const root = resolveRoot(config.root, configDir);\n try {\n await access(root);\n checks.push({\n name: 'root directory',\n severity: 'ok',\n message: root\n });\n } catch {\n checks.push({\n name: 'root directory',\n severity: 'fail',\n message: `${root} does not exist (mkdir -p it or fix root in config)`\n });\n }\n\n const types = new Set(Object.values(config.forges).map((f) => f.type));\n const needsGit = types.has('git') || types.size > 0;\n const needsGh = types.has('github');\n\n if (needsGit) {\n checks.push(\n (await hasCommand('git'))\n ? { name: 'git CLI', severity: 'ok', message: 'on PATH' }\n : {\n name: 'git CLI',\n severity: 'fail',\n message: 'install from https://git-scm.com/'\n }\n );\n }\n\n if (needsGh) {\n if (await hasCommand('gh')) {\n checks.push({ name: 'gh CLI', severity: 'ok', message: 'on PATH' });\n const auth = await execCapture('gh', ['auth', 'status']);\n checks.push(\n auth.code === 0\n ? { name: 'gh auth', severity: 'ok', message: 'authenticated' }\n : {\n name: 'gh auth',\n severity: 'warn',\n message: 'not logged in — run `gh auth login`'\n }\n );\n } else {\n checks.push({\n name: 'gh CLI',\n severity: 'fail',\n message: 'install from https://cli.github.com/'\n });\n }\n }\n\n return checks;\n}\n\nfunction severitySymbol(severity: CheckSeverity): string {\n if (severity === 'ok') return colors.green('✓');\n if (severity === 'warn') return colors.yellow('!');\n return colors.red('✗');\n}\n\nexport const validateCommand = defineCommand({\n meta: {\n name: 'validate',\n description:\n 'Preflight: check the config schema, required CLI tools, and root directory'\n },\n args: {\n json: {\n type: 'boolean',\n description: 'Emit a machine-readable JSON report',\n default: false\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const checks = await runChecks(loaded.config, configDir);\n const ok = checks.every((c) => c.severity !== 'fail');\n\n if (args.json) {\n process.stdout.write(`${JSON.stringify({ ok, checks }, null, 2)}\\n`);\n } else {\n for (const c of checks) {\n process.stdout.write(\n `${severitySymbol(c.severity)} ${c.name.padEnd(22)} ${colors.dim(c.message)}\\n`\n );\n }\n process.stdout.write(\n `\\n${ok ? colors.green('All checks passed.') : colors.red('Validation failed.')}\\n`\n );\n }\n\n if (!ok) {\n process.exitCode = 1;\n return;\n }\n if (!loaded.configFile) {\n consola.warn(\n 'No forgemap.config.ts found — using built-in defaults. Run `forgemap config init` to materialize one.'\n );\n }\n }\n});\n","import { type ArgsDef, type CommandDef, defineCommand } from 'citty';\nimport consola from 'consola';\nimport {\n type Shell,\n SUPPORTED_SHELLS as SUPPORTED,\n detectShell,\n installRcBlock\n} from '../utils/shell.ts';\nimport { cdCommand } from './cd.ts';\nimport { cleanupCommand } from './cleanup.ts';\nimport { cloneCommand } from './clone.ts';\nimport { configCommand } from './config/index.ts';\nimport { deleteCommand } from './delete.ts';\nimport { forgeCommand } from './forge/index.ts';\nimport { importCommand } from './import.ts';\nimport { infoCommand } from './info.ts';\nimport { listCommand } from './list.ts';\nimport { openCommand } from './open.ts';\nimport { pathCommand } from './path.ts';\nimport { pickCommand } from './pick.ts';\nimport { shellInitCommand } from './shell-init.ts';\nimport { statusCommand } from './status.ts';\nimport { syncCommand } from './sync.ts';\nimport { validateCommand } from './validate.ts';\n\n// Commands whose depth-2 positional is a repo slug: these complete against the\n// live `forgemap list --format slug` output (the one dynamic value source).\nconst SLUG_COMMANDS = ['clone', 'cd', 'path', 'open', 'list', 'pick', 'delete'];\n\n// Fixed value sets a command validates internally. citty's arg metadata carries\n// no enum options for these — they are declared `type: 'string'` and checked in\n// each command's `run()` — so the value lists are curated here, keyed by\n// subcommand then flag, sitting next to the flags they annotate. Flag *names*\n// are derived from the definitions below and need no upkeep; only these static\n// value sets do.\nconst STATIC_FLAG_VALUES: Record<string, Record<string, string[]>> = {\n list: { '--format': ['auto', 'pretty', 'path', 'slug'] },\n status: { '--format': ['pretty', 'json'] },\n import: { '--format': ['pretty', 'json'], '--type': ['forgemap'] }\n};\n\n// Commands whose leading positional is a shell flavor (completed statically\n// from the supported-shells list rather than hardcoded here).\nconst SHELL_POSITIONAL = new Set(['completion', 'shell-init']);\n\n// Commands in the registry have heterogeneous arg shapes; `CommandDef<any>` is\n// how citty itself types such collections (see its `SubCommandsDef`).\ntype AnyCommand = CommandDef<any>;\n\ninterface CommandSpec {\n name: string;\n /** Flag names (`--foo`, plus `--no-foo` for negatable booleans). */\n flags: string[];\n /** Static value sets for flags that take a fixed enum (e.g. `--format`). */\n flagValues: Record<string, string[]>;\n /** Static values for the leading positional (shell flavors), if any. */\n positionalValues: string[];\n /** Whether the leading positional completes against repo slugs. */\n slugs: boolean;\n}\n\n/** Every forgemap command declares `args` as a plain object literal (or omits\n * it, like `config`), never a thunk — so no `Resolvable` unwrapping is needed. */\nfunction argsOf(cmd: AnyCommand): ArgsDef {\n return (cmd.args ?? {}) as ArgsDef;\n}\n\n/** Flag names a command exposes, derived from its `defineCommand` args so a new\n * flag surfaces in completion automatically. Positionals are handled\n * separately; negatable booleans (those with a `negativeDescription`) also get\n * their `--no-<flag>` form. */\nfunction flagsOf(cmd: AnyCommand): string[] {\n const flags: string[] = [];\n for (const [name, def] of Object.entries(argsOf(cmd))) {\n if (def.type === 'positional') continue;\n flags.push(`--${name}`);\n if (def.type === 'boolean' && def.negativeDescription) {\n flags.push(`--no-${name}`);\n }\n }\n return flags;\n}\n\n/** The ordered subcommand registry, mirroring `rootCommand.subCommands` in\n * cli.ts. It is kept here rather than imported from cli.ts because that would\n * form a cycle (cli → completion → cli). Built lazily so the self-reference to\n * `completionCommand` resolves after the module finishes initializing. */\nfunction commandSpecs(): CommandSpec[] {\n const registry: Array<readonly [string, AnyCommand]> = [\n ['clone', cloneCommand],\n ['import', importCommand],\n ['cleanup', cleanupCommand],\n ['delete', deleteCommand],\n ['cd', cdCommand],\n ['path', pathCommand],\n ['open', openCommand],\n ['list', listCommand],\n ['pick', pickCommand],\n ['status', statusCommand],\n ['sync', syncCommand],\n ['validate', validateCommand],\n ['info', infoCommand],\n ['completion', completionCommand],\n ['shell-init', shellInitCommand],\n ['config', configCommand],\n ['forge', forgeCommand]\n ];\n return registry.map(([name, cmd]) => ({\n name,\n flags: flagsOf(cmd),\n flagValues: STATIC_FLAG_VALUES[name] ?? {},\n positionalValues: SHELL_POSITIONAL.has(name) ? [...SUPPORTED] : [],\n slugs: SLUG_COMMANDS.includes(name)\n }));\n}\n\nfunction flagValuePairs(\n specs: CommandSpec[]\n): Array<[string, string, string[]]> {\n return specs.flatMap((s) =>\n Object.entries(s.flagValues).map(\n ([flag, values]) => [s.name, flag, values] as [string, string, string[]]\n )\n );\n}\n\nfunction renderBash(specs: CommandSpec[]): string {\n const names = specs.map((s) => s.name).join(' ');\n\n const valueArms = flagValuePairs(specs)\n .map(\n ([cmd, flag, values]) =>\n ` ${cmd}:${flag}) COMPREPLY=( $(compgen -W \"${values.join(' ')}\" -- \"$cur\") ); return ;;`\n )\n .join('\\n');\n\n const flagArms = specs\n .filter((s) => s.flags.length > 0)\n .map((s) => ` ${s.name}) flags=\"${s.flags.join(' ')}\" ;;`)\n .join('\\n');\n\n const slugCmds = specs.filter((s) => s.slugs).map((s) => s.name);\n const positionalArms = [\n slugCmds.length > 0\n ? ` ${slugCmds.join('|')})\n local slugs\n slugs=$(forgemap list --format slug 2>/dev/null)\n COMPREPLY=( $(compgen -W \"$slugs\" -- \"$cur\") )\n ;;`\n : '',\n ...specs\n .filter((s) => s.positionalValues.length > 0)\n .map(\n (s) =>\n ` ${s.name}) COMPREPLY=( $(compgen -W \"${s.positionalValues.join(' ')}\" -- \"$cur\") ) ;;`\n )\n ]\n .filter(Boolean)\n .join('\\n');\n\n return `# forgemap bash completion — drop into your ~/.bashrc:\n# eval \"$(forgemap completion bash)\"\n_forgemap_completion() {\n local cur prev cmd flags\n COMPREPLY=()\n cur=\"\\${COMP_WORDS[COMP_CWORD]}\"\n prev=\"\\${COMP_WORDS[COMP_CWORD-1]}\"\n cmd=\"\\${COMP_WORDS[1]}\"\n\n if [ \"$COMP_CWORD\" = \"1\" ]; then\n COMPREPLY=( $(compgen -W \"${names}\" -- \"$cur\") )\n return\n fi\n\n # Values for flags with a fixed set (e.g. --format), keyed by \"<cmd>:<flag>\".\n case \"$cmd:$prev\" in\n${valueArms}\n esac\n\n # Flag names for the current subcommand.\n if [[ \"$cur\" == -* ]]; then\n case \"$cmd\" in\n${flagArms}\n esac\n COMPREPLY=( $(compgen -W \"$flags\" -- \"$cur\") )\n return\n fi\n\n # Positional values (repo slugs, or a shell name).\n case \"$cmd\" in\n${positionalArms}\n esac\n}\ncomplete -F _forgemap_completion forgemap\n`;\n}\n\nfunction renderZsh(specs: CommandSpec[]): string {\n const subcommands = specs.map((s) => `'${s.name}'`).join(' ');\n\n const valueArms = flagValuePairs(specs)\n .map(\n ([cmd, flag, values]) =>\n ` ${cmd}:${flag}) compadd ${values.join(' ')}; return ;;`\n )\n .join('\\n');\n\n const flagArms = specs\n .filter((s) => s.flags.length > 0)\n .map((s) => ` ${s.name}) compadd -- ${s.flags.join(' ')}; return ;;`)\n .join('\\n');\n\n const slugCmds = specs\n .filter((s) => s.slugs)\n .map((s) => s.name)\n .join('|');\n const shellArms = specs\n .filter((s) => s.positionalValues.length > 0)\n .map((s) => ` ${s.name}) compadd ${s.positionalValues.join(' ')} ;;`)\n .join('\\n');\n\n return `# forgemap zsh completion — drop into your ~/.zshrc:\n# eval \"$(forgemap completion zsh)\"\n_forgemap() {\n local -a subcommands\n subcommands=(${subcommands})\n local cmd=\"\\${words[2]}\"\n local prev=\"\\${words[CURRENT-1]}\"\n local cur=\"\\${words[CURRENT]}\"\n\n if (( CURRENT == 2 )); then\n _describe 'forgemap subcommand' subcommands\n return\n fi\n\n # Values for flags with a fixed set (e.g. --format), keyed by \"<cmd>:<flag>\".\n case \"$cmd:$prev\" in\n${valueArms}\n esac\n\n # Flag names for the current subcommand.\n if [[ \"$cur\" == -* ]]; then\n case \"$cmd\" in\n${flagArms}\n esac\n return\n fi\n\n # Positional values (repo slugs, or a shell name).\n case \"$cmd\" in\n ${slugCmds})\n local -a slugs\n slugs=(\"\\${(@f)$(forgemap list --format slug 2>/dev/null)}\")\n _describe 'slug' slugs\n ;;\n${shellArms}\n esac\n}\ncompdef _forgemap forgemap\n`;\n}\n\nfunction renderFish(specs: CommandSpec[]): string {\n const names = specs.map((s) => s.name).join(' ');\n\n const flagLines = specs\n .flatMap((s) =>\n s.flags.map((flag) => {\n const long = flag.replace(/^--/, '');\n const values = s.flagValues[flag];\n const valuePart = values ? ` -x -a '${values.join(' ')}'` : '';\n return `complete -c forgemap -n '__fish_seen_subcommand_from ${s.name}' -l ${long}${valuePart}`;\n })\n )\n .join('\\n');\n\n const shellCmds = specs.filter((s) => s.positionalValues.length > 0);\n const shellCmdsList = shellCmds.map((s) => `\"${s.name}\"`).join(' ');\n // Both shell-positional commands share the supported-shells value set.\n const shellValues = shellCmds[0]?.positionalValues.join(' ') ?? '';\n\n const slugCmdsList = specs\n .filter((s) => s.slugs)\n .map((s) => `\"${s.name}\"`)\n .join(' ');\n\n return `# forgemap fish completion — drop into your ~/.config/fish/config.fish:\n# forgemap completion fish | source\n\n# Subcommands (depth 1).\ncomplete -c forgemap -f -n '__fish_use_subcommand' -a '${names}'\n\n# Flags per subcommand (with fixed value sets where applicable).\n${flagLines}\n\n# Shell flavor for completion / shell-init (depth 2).\nfunction __forgemap_needs_shell\n set -l tokens (commandline -opc)\n set -l shell_cmds ${shellCmdsList}\n if test (count $tokens) -ge 2; and contains $tokens[2] $shell_cmds\n return 0\n end\n return 1\nend\ncomplete -c forgemap -f -n '__forgemap_needs_shell' -a '${shellValues}'\n\n# Slugs (depth 2) for commands that take one.\nfunction __forgemap_needs_slug\n set -l tokens (commandline -opc)\n set -l slug_cmds ${slugCmdsList}\n if test (count $tokens) -ge 2; and contains $tokens[2] $slug_cmds\n return 0\n end\n return 1\nend\n\ncomplete -c forgemap -f -n '__forgemap_needs_slug' \\\\\n -a '(forgemap list --format slug 2>/dev/null)'\n`;\n}\n\nexport const completionCommand = defineCommand({\n meta: {\n name: 'completion',\n description:\n 'Print a shell completion script. Source via `eval \"$(forgemap completion)\"`.'\n },\n args: {\n shell: {\n type: 'positional',\n description: `Shell flavor (${SUPPORTED.join(', ')}). Auto-detected from $SHELL if omitted.`,\n required: false\n },\n install: {\n type: 'boolean',\n description:\n \"Append the completion loader to your shell's rc file (idempotent) instead of printing\",\n default: false\n }\n },\n async run({ args }) {\n const requested = (args.shell ?? detectShell()) as Shell;\n if (!SUPPORTED.includes(requested)) {\n consola.error(\n `Unsupported shell \"${requested}\". Supported: ${SUPPORTED.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n\n if (args.install) {\n const loader =\n requested === 'fish'\n ? 'forgemap completion fish | source'\n : `eval \"$(forgemap completion ${requested})\"`;\n const { status, rcFile } = await installRcBlock(requested, 'completion', [\n loader\n ]);\n if (status === 'present') {\n consola.info(`forgemap completion already present in ${rcFile}.`);\n } else {\n const verb = status === 'updated' ? 'Updated' : 'Added';\n consola.success(`${verb} forgemap completion in ${rcFile}.`);\n consola.info(\n `Run \\`source ${rcFile}\\` or restart your shell to activate it.`\n );\n }\n return;\n }\n\n const specs = commandSpecs();\n const out =\n requested === 'fish'\n ? renderFish(specs)\n : requested === 'zsh'\n ? renderZsh(specs)\n : renderBash(specs);\n process.stdout.write(out);\n }\n});\n","import { defineCommand } from 'citty';\nimport { cdCommand } from './commands/cd.ts';\nimport { cleanupCommand } from './commands/cleanup.ts';\nimport { cloneCommand } from './commands/clone.ts';\nimport { completionCommand } from './commands/completion.ts';\nimport { configCommand } from './commands/config/index.ts';\nimport { deleteCommand } from './commands/delete.ts';\nimport { forgeCommand } from './commands/forge/index.ts';\nimport { importCommand } from './commands/import.ts';\nimport { infoCommand } from './commands/info.ts';\nimport { listCommand } from './commands/list.ts';\nimport { openCommand } from './commands/open.ts';\nimport { pathCommand } from './commands/path.ts';\nimport { pickCommand } from './commands/pick.ts';\nimport { shellInitCommand } from './commands/shell-init.ts';\nimport { statusCommand } from './commands/status.ts';\nimport { syncCommand } from './commands/sync.ts';\nimport { validateCommand } from './commands/validate.ts';\n\n// Injected at build time by vite's `define` (see vite.config.ts), sourced from\n// package.json's `version`. release-please bumps that field on release, so the\n// reported version tracks the published one instead of a hand-copied literal\n// that would silently drift.\ndeclare const __APP_VERSION__: string;\n\nexport const rootCommand = defineCommand({\n meta: {\n name: 'forgemap',\n version: __APP_VERSION__,\n description:\n 'Manage a local repo layout of the form <root>/<forge.dir>/<owner>/<repo>'\n },\n subCommands: {\n clone: cloneCommand,\n import: importCommand,\n cleanup: cleanupCommand,\n delete: deleteCommand,\n cd: cdCommand,\n path: pathCommand,\n open: openCommand,\n list: listCommand,\n pick: pickCommand,\n status: statusCommand,\n sync: syncCommand,\n validate: validateCommand,\n info: infoCommand,\n completion: completionCommand,\n 'shell-init': shellInitCommand,\n config: configCommand,\n forge: forgeCommand\n }\n});\n","import { runMain } from 'citty';\nimport { rootCommand } from '../cli.ts';\n\nrunMain(rootCommand);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"forgemap.mjs","names":[],"sources":["../../src/commands/cd.ts","../../src/utils/path.ts","../../src/config/load.ts","../../src/repos/scan.ts","../../src/repos/cache.ts","../../src/utils/exec.ts","../../src/forges/git.ts","../../src/utils/concurrency.ts","../../src/forges/github.ts","../../src/forges/registry.ts","../../src/slug/parse.ts","../../src/repos/git.ts","../../src/repos/evaluate.ts","../../src/commands/cleanup.ts","../../src/slug/resolve.ts","../../src/commands/clone.ts","../../src/utils/shell.ts","../../src/config/write.ts","../../src/commands/config/init.ts","../../src/commands/config/show.ts","../../src/commands/config/index.ts","../../src/commands/delete.ts","../../src/config/forges.ts","../../src/config/mutate.ts","../../src/repos/picker.ts","../../src/commands/forge/shared.ts","../../src/commands/forge/add.ts","../../src/commands/forge/edit.ts","../../src/commands/forge/remove.ts","../../src/commands/forge/index.ts","../../src/repos/import.ts","../../src/commands/import.ts","../../src/commands/info.ts","../../src/repos/filter.ts","../../src/repos/match.ts","../../src/commands/list.ts","../../src/slug/locate.ts","../../src/commands/open.ts","../../src/commands/path.ts","../../src/commands/pick.ts","../../src/commands/shell-init.ts","../../src/commands/status.ts","../../src/commands/sync.ts","../../src/commands/validate.ts","../../src/commands/completion.ts","../../src/cli.ts","../../src/bin/forgemap.ts"],"sourcesContent":["import { defineCommand } from 'citty';\nimport consola from 'consola';\n\n/**\n * When the shell wrapper from `forgemap shell-init` is sourced, it\n * intercepts `forgemap cd <slug>` before the binary is called and runs\n * the actual `cd` in the user's shell. If the binary itself ever runs\n * this command, the wrapper isn't active — we print a hint so the user\n * knows how to enable it.\n */\nexport const cdCommand = defineCommand({\n meta: {\n name: 'cd',\n description: 'Change directory into a repo (requires shell integration)'\n },\n args: {\n slug: {\n type: 'positional',\n description: 'owner/repo, forge:owner/repo, full URL, or fuzzy query',\n required: false\n }\n },\n async run() {\n consola.error(\n 'forgemap cd needs shell integration to actually change directory.'\n );\n consola.info('Source the wrapper once and try again:');\n consola.info(' eval \"$(forgemap shell-init)\" # zsh/bash');\n consola.info(' forgemap shell-init fish | source # fish');\n consola.info(\n 'Or, if you just want the path on stdout, use: forgemap path <slug>'\n );\n process.exitCode = 1;\n }\n});\n","import { homedir } from 'node:os';\nimport { isAbsolute, resolve } from 'pathe';\n\nexport function expandTilde(p: string): string {\n if (p === '~') return homedir();\n if (p.startsWith('~/')) return resolve(homedir(), p.slice(2));\n return p;\n}\n\nexport function resolveRoot(root: string, configDir: string): string {\n const expanded = expandTilde(root);\n if (isAbsolute(expanded)) return expanded;\n return resolve(configDir, expanded);\n}\n","import { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { loadConfig } from 'c12';\nimport { dirname, join, resolve } from 'pathe';\nimport type { ForgeMapConfig, ForgeMapUserConfig } from './schema.ts';\n\nconst CONFIG_BASENAMES = [\n 'forgemap.config.ts',\n 'forgemap.config.mts',\n 'forgemap.config.cts',\n 'forgemap.config.js',\n 'forgemap.config.mjs',\n 'forgemap.config.cjs',\n 'forgemap.config.json'\n];\n\n/** Walk up from `start` to the filesystem root looking for a forgemap config. */\nfunction findConfigUp(start: string): string | undefined {\n let dir = resolve(start);\n for (;;) {\n for (const base of CONFIG_BASENAMES) {\n const candidate = join(dir, base);\n if (existsSync(candidate)) return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n}\n\n/** Fallback config under $XDG_CONFIG_HOME/forgemap (or ~/.config/forgemap). */\nfunction findGlobalConfig(): string | undefined {\n const base = process.env.XDG_CONFIG_HOME || join(homedir(), '.config');\n const dir = join(base, 'forgemap');\n for (const baseName of CONFIG_BASENAMES) {\n const candidate = join(dir, baseName);\n if (existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n\nexport interface ConfigFileCandidate {\n path: string;\n /** Which discovery step surfaced it. */\n source: 'walk-up' | 'global';\n}\n\n/**\n * Every `forgemap.config.*` a change could be written to, in resolution order:\n * one per directory walking up from `start` (nearest first, mirroring the\n * loader's first-basename-wins rule), then the global config. Used by the\n * `forge` command to let the user pick a target when more than one exists.\n */\nexport function discoverConfigFiles(\n start: string = process.cwd()\n): ConfigFileCandidate[] {\n const found: ConfigFileCandidate[] = [];\n const seen = new Set<string>();\n let dir = resolve(start);\n for (;;) {\n for (const base of CONFIG_BASENAMES) {\n const candidate = join(dir, base);\n if (existsSync(candidate)) {\n seen.add(candidate);\n found.push({ path: candidate, source: 'walk-up' });\n break;\n }\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n const global = findGlobalConfig();\n if (global && !seen.has(global)) {\n found.push({ path: global, source: 'global' });\n }\n return found;\n}\n\n/**\n * Which of the four discovery steps produced the resolved config file:\n * `--config` flag → `FORGEMAP_CONFIG` env → walk-up from cwd → global fallback.\n * `default` means none matched and the built-in defaults are in effect.\n */\nexport type ConfigSource = 'flag' | 'env' | 'walk-up' | 'global' | 'default';\n\nexport interface LoadedConfig {\n config: ForgeMapConfig;\n configFile: string | undefined;\n cwd: string;\n /** The discovery step that found `configFile`, or `default` when none did. */\n source: ConfigSource;\n}\n\nconst DEFAULT_CONFIG: ForgeMapConfig = {\n root: '.',\n defaultForge: 'github',\n forges: {\n github: {\n type: 'github',\n host: 'github.com',\n dir: 'comGithub'\n }\n }\n};\n\nexport interface LoadOptions {\n cwd?: string;\n configFile?: string;\n}\n\nexport async function loadForgeMapConfig(\n options: LoadOptions = {}\n): Promise<LoadedConfig> {\n const envConfig = process.env.FORGEMAP_CONFIG;\n const startDir = options.cwd ?? process.cwd();\n // Resolution order: explicit flag → env → walk up from cwd → global fallback.\n // Track which step matched so callers (e.g. `info`) can report the origin.\n let explicit: string | undefined;\n let source: ConfigSource;\n if (options.configFile) {\n explicit = options.configFile;\n source = 'flag';\n } else if (envConfig) {\n explicit = envConfig;\n source = 'env';\n } else {\n const walkedUp = findConfigUp(startDir);\n if (walkedUp) {\n explicit = walkedUp;\n source = 'walk-up';\n } else {\n const global = findGlobalConfig();\n if (global) {\n explicit = global;\n source = 'global';\n } else {\n explicit = undefined;\n source = 'default';\n }\n }\n }\n // Resolve before handing it to c12 — `cwd` is derived from it, so a relative\n // path would be resolved a second time against that cwd and end up nested.\n if (explicit) explicit = resolve(startDir, explicit);\n const cwd = explicit ? dirname(explicit) : startDir;\n\n // No `defaults:` here — c12 would deep-merge them into the user\n // config (forges in particular), which surfaces the built-in github\n // forge in every custom layout. We apply defaults below ourselves,\n // only filling in missing top-level fields.\n const { config, configFile } = await loadConfig<ForgeMapUserConfig>({\n name: 'forgemap',\n cwd,\n configFile: explicit ? explicit : 'forgemap.config',\n rcFile: false,\n globalRc: false,\n dotenv: false\n });\n\n // User-defined forges replace the defaults entirely — otherwise the\n // built-in github fallback would pollute every custom config and\n // commands like `validate` would demand `gh` even when no github\n // forge is configured.\n const merged: ForgeMapConfig = {\n root: config.root ?? DEFAULT_CONFIG.root,\n defaultForge: config.defaultForge ?? DEFAULT_CONFIG.defaultForge,\n forges:\n config.forges && Object.keys(config.forges).length > 0\n ? config.forges\n : DEFAULT_CONFIG.forges\n };\n\n // When nothing was discovered, c12 still echoes back the fallback base name\n // (\"forgemap.config\") as `configFile` — a path that does not exist. Treat that\n // as \"no file\" so callers report the built-in defaults honestly.\n const resolvedFile =\n source === 'default' ? undefined : configFile || undefined;\n\n return {\n config: merged,\n configFile: resolvedFile,\n cwd,\n source: resolvedFile ? source : 'default'\n };\n}\n","import { readdir } from 'node:fs/promises';\nimport { join } from 'pathe';\nimport type { ForgeConfig, ForgeMapConfig } from '../config/schema.ts';\nimport { resolveRoot } from '../utils/path.ts';\n\nexport interface ScannedRepo {\n forgeName: string;\n forge: ForgeConfig;\n owner: string;\n repo: string;\n localPath: string;\n /** Convenience: `<owner>/<repo>` */\n slug: string;\n}\n\nasync function listDirs(path: string): Promise<string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => e.name);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw error;\n }\n}\n\nexport interface ScanOptions {\n config: ForgeMapConfig;\n configDir: string;\n}\n\nexport async function scanRepos(options: ScanOptions): Promise<ScannedRepo[]> {\n const { config, configDir } = options;\n const root = resolveRoot(config.root, configDir);\n const repos: ScannedRepo[] = [];\n\n for (const [forgeName, forge] of Object.entries(config.forges)) {\n const forgeRoot = join(root, forge.dir);\n const owners = await listDirs(forgeRoot);\n for (const owner of owners) {\n const ownerPath = join(forgeRoot, owner);\n const repoNames = await listDirs(ownerPath);\n for (const repo of repoNames) {\n repos.push({\n forgeName,\n forge,\n owner,\n repo,\n localPath: join(ownerPath, repo),\n slug: `${owner}/${repo}`\n });\n }\n }\n }\n\n return repos;\n}\n","import { createHash } from 'node:crypto';\nimport { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'pathe';\nimport type { ForgeMapConfig } from '../config/schema.ts';\nimport { resolveRoot } from '../utils/path.ts';\nimport { type ScannedRepo, scanRepos } from './scan.ts';\n\n/**\n * Cache lifecycle:\n *\n * 1. Hot path (age < TTL): trust the file, return repos directly.\n * No stat calls, no fingerprint walk — ~1 ms.\n *\n * 2. Cold path (age ≥ TTL): walk the layout (in parallel) and compare\n * against the stored fingerprint. On match, bump the timestamp and\n * return cached repos. On mismatch, rescan and rewrite the cache.\n *\n * 3. Incremental updates (appendCachedRepo / removeCachedRepo):\n * forgemap-driven changes (clone, remove) edit the cache in-place\n * so the next read stays on the hot path. Used to skip rebuild\n * when forgemap itself is the source of truth.\n *\n * Set FORGEMAP_CACHE_TTL_MS (default 60 000) to override the TTL.\n */\ninterface CacheFile {\n fingerprint: string;\n writtenAt: number;\n repos: ScannedRepo[];\n}\n\nconst DEFAULT_TTL_MS = 60_000;\n\nfunction ttl(): number {\n const env = process.env.FORGEMAP_CACHE_TTL_MS;\n if (!env) return DEFAULT_TTL_MS;\n const parsed = Number.parseInt(env, 10);\n return Number.isFinite(parsed) && parsed >= 0 ? parsed : DEFAULT_TTL_MS;\n}\n\nfunction cacheDir(): string {\n const xdg = process.env.XDG_CACHE_HOME;\n return xdg ? join(xdg, 'forgemap') : join(homedir(), '.cache', 'forgemap');\n}\n\nfunction cachePath(root: string): string {\n const hash = createHash('sha1').update(root).digest('hex').slice(0, 16);\n return join(cacheDir(), `scan-${hash}.json`);\n}\n\nasync function safeStat(path: string): Promise<number> {\n try {\n const s = await stat(path);\n return Math.trunc(s.mtimeMs);\n } catch {\n return 0;\n }\n}\n\nasync function safeListDirs(path: string): Promise<string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => e.name);\n } catch {\n return [];\n }\n}\n\n/** `[path, marker]` — the marker is whatever identifies that level's state. */\ntype FingerprintEntry = [string, string];\n\n/**\n * Fingerprint of the layout: directory mtimes for root, forge.dir and\n * every owner, plus the repo names each owner holds. Catches new clones\n * / removals at any of those levels. Stops short of stat-ing each repo\n * dir — that would mostly duplicate the scan it's meant to avoid.\n *\n * The repo names are what make the check reliable. An owner's mtime\n * alone is not enough: a repo cloned beside an existing one moves only\n * that mtime, and mtimes are compared at millisecond granularity, so\n * two clones landing inside the same millisecond hash identically and\n * a stale cache wins. Listing the names makes invalidation independent\n * of clock and filesystem timestamp resolution.\n *\n * Stats are issued in parallel: one batch per forge for its forge.dir +\n * owner list, all forges in parallel. Beats the sequential version by\n * an order of magnitude at thousands of owners.\n */\nexport async function computeFingerprint(\n config: ForgeMapConfig,\n configDir: string\n): Promise<string> {\n const root = resolveRoot(config.root, configDir);\n\n const perForge = await Promise.all(\n Object.values(config.forges).map(async (forge) => {\n const forgeRoot = join(root, forge.dir);\n const [forgeMtime, owners] = await Promise.all([\n safeStat(forgeRoot),\n safeListDirs(forgeRoot)\n ]);\n const ownerEntries = await Promise.all(\n owners.map(async (owner) => {\n const ownerPath = join(forgeRoot, owner);\n const [mtime, repos] = await Promise.all([\n safeStat(ownerPath),\n safeListDirs(ownerPath)\n ]);\n // readdir order is filesystem-dependent — sort for a stable hash.\n // JSON quoting keeps names holding ':' or a newline unambiguous.\n const marker = `${mtime}:${JSON.stringify(repos.sort())}`;\n return [ownerPath, marker] as FingerprintEntry;\n })\n );\n return [\n [forgeRoot, String(forgeMtime)] as FingerprintEntry,\n ...ownerEntries\n ];\n })\n );\n\n const entries: FingerprintEntry[] = [[root, String(await safeStat(root))]];\n for (const group of perForge) entries.push(...group);\n\n entries.sort((a, b) => a[0].localeCompare(b[0]));\n return createHash('sha1')\n .update(entries.map(([p, marker]) => `${p}:${marker}`).join('\\n'))\n .digest('hex');\n}\n\nasync function readCacheFile(file: string): Promise<CacheFile | null> {\n try {\n const raw = await readFile(file, 'utf8');\n return JSON.parse(raw) as CacheFile;\n } catch {\n return null;\n }\n}\n\nasync function writeCacheFile(file: string, payload: CacheFile): Promise<void> {\n await mkdir(cacheDir(), { recursive: true });\n await writeFile(file, JSON.stringify(payload), 'utf8');\n}\n\nexport interface ScanCachedOptions {\n config: ForgeMapConfig;\n configDir: string;\n /** Default true. Set false to force a full re-scan and rewrite. */\n useCache?: boolean;\n /** Default true. Set false to skip the TTL fast-path and always validate the fingerprint. */\n trustTtl?: boolean;\n}\n\nexport async function scanReposCached(\n options: ScanCachedOptions\n): Promise<ScannedRepo[]> {\n const { config, configDir, useCache = true, trustTtl = true } = options;\n const root = resolveRoot(config.root, configDir);\n const file = cachePath(root);\n\n if (useCache) {\n const cached = await readCacheFile(file);\n if (cached) {\n const age = Date.now() - cached.writtenAt;\n if (trustTtl && age < ttl()) {\n return cached.repos;\n }\n const fingerprint = await computeFingerprint(config, configDir);\n if (cached.fingerprint === fingerprint) {\n // Still accurate — refresh the timestamp so the next reader can hot-path.\n await writeCacheFile(file, { ...cached, writtenAt: Date.now() });\n return cached.repos;\n }\n }\n }\n\n const repos = await scanRepos({ config, configDir });\n const fingerprint = await computeFingerprint(config, configDir);\n await writeCacheFile(file, {\n fingerprint,\n writtenAt: Date.now(),\n repos\n });\n return repos;\n}\n\n/**\n * Append a freshly-cloned repo to the cache without touching the\n * filesystem. Lets `forgemap clone` keep the cache warm so the next\n * read still hits the TTL fast-path.\n */\nexport async function appendCachedRepo(\n options: ScanCachedOptions,\n repo: ScannedRepo\n): Promise<void> {\n const { config, configDir } = options;\n const root = resolveRoot(config.root, configDir);\n const file = cachePath(root);\n const cached = await readCacheFile(file);\n if (!cached) {\n return; // no cache yet — next scan will pick the new repo up naturally\n }\n if (cached.repos.some((r) => r.localPath === repo.localPath)) {\n return;\n }\n await writeCacheFile(file, {\n fingerprint: await computeFingerprint(config, configDir),\n writtenAt: Date.now(),\n repos: [...cached.repos, repo]\n });\n}\n\n/**\n * Inverse of appendCachedRepo for a future `forgemap remove`.\n */\nexport async function removeCachedRepo(\n options: ScanCachedOptions,\n localPath: string\n): Promise<void> {\n const { config, configDir } = options;\n const root = resolveRoot(config.root, configDir);\n const file = cachePath(root);\n const cached = await readCacheFile(file);\n if (!cached) return;\n const next = cached.repos.filter((r) => r.localPath !== localPath);\n if (next.length === cached.repos.length) return;\n await writeCacheFile(file, {\n fingerprint: await computeFingerprint(config, configDir),\n writtenAt: Date.now(),\n repos: next\n });\n}\n\n// Exported for tests.\nexport const __test = { cacheDir, cachePath };\n","import { spawn } from 'node:child_process';\n\nexport interface ExecResult {\n code: number;\n}\n\nexport function execInherit(\n command: string,\n args: string[]\n): Promise<ExecResult> {\n return new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(command, args, { stdio: 'inherit' });\n child.on('error', rejectPromise);\n child.on('close', (code) => {\n resolvePromise({ code: code ?? 0 });\n });\n });\n}\n\nexport interface CaptureResult {\n code: number;\n stdout: string;\n stderr: string;\n /** True when the process was killed because it exceeded `timeoutMs`. */\n timedOut?: boolean;\n}\n\nexport interface CaptureOptions {\n cwd?: string;\n /** Kill the process after this many ms and resolve with `timedOut: true`. */\n timeoutMs?: number;\n /** Extra env vars, merged over `process.env`. */\n env?: NodeJS.ProcessEnv;\n}\n\nexport function execCapture(\n command: string,\n args: string[],\n options: CaptureOptions = {}\n): Promise<CaptureResult> {\n return new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n env: options.env ? { ...process.env, ...options.env } : undefined,\n stdio: ['ignore', 'pipe', 'pipe']\n });\n let stdout = '';\n let stderr = '';\n let timedOut = false;\n let settled = false;\n\n let timer: NodeJS.Timeout | undefined;\n let killer: NodeJS.Timeout | undefined;\n if (options.timeoutMs && options.timeoutMs > 0) {\n timer = setTimeout(() => {\n timedOut = true;\n child.kill('SIGTERM');\n // Escalate if it ignores SIGTERM (e.g. a wedged ssh child).\n killer = setTimeout(() => child.kill('SIGKILL'), 2000);\n killer.unref();\n }, options.timeoutMs);\n timer.unref();\n }\n\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n child.on('error', (error) => {\n if (timer) clearTimeout(timer);\n if (killer) clearTimeout(killer);\n if (!settled) {\n settled = true;\n rejectPromise(error);\n }\n });\n child.on('close', (code) => {\n if (timer) clearTimeout(timer);\n if (killer) clearTimeout(killer);\n if (!settled) {\n settled = true;\n // A signal kill reports code null; surface a non-zero code so callers\n // that only inspect `code` don't mistake a timeout for success.\n resolvePromise({\n code: code ?? (timedOut ? 124 : 0),\n stdout,\n stderr,\n timedOut\n });\n }\n });\n });\n}\n\nexport function hasCommand(command: string): Promise<boolean> {\n return new Promise((resolvePromise) => {\n const child = spawn(\n process.platform === 'win32' ? 'where' : 'which',\n [command],\n {\n stdio: 'ignore'\n }\n );\n child.on('error', () => resolvePromise(false));\n child.on('close', (code) => resolvePromise(code === 0));\n });\n}\n","import type {\n ForgeConfig,\n GitForgeConfig,\n GitProtocol\n} from '../config/schema.ts';\nimport { execCapture, execInherit, hasCommand } from '../utils/exec.ts';\nimport type {\n CloneOptions,\n ForgeAdapter,\n RemoteCheckInput,\n RemoteCheckResult\n} from './types.ts';\n\ninterface UrlParts {\n forge: ForgeConfig;\n owner: string;\n repo: string;\n protocol?: GitProtocol;\n}\n\nconst REMOTE_TIMEOUT_MS = 10_000;\n\nfunction buildCloneUrl(opts: UrlParts): string {\n const forge = opts.forge as GitForgeConfig;\n const protocol = opts.protocol ?? forge.protocol ?? 'ssh';\n if (protocol === 'https') {\n return `https://${forge.host}/${opts.owner}/${opts.repo}.git`;\n }\n return `git@${forge.host}:${opts.owner}/${opts.repo}.git`;\n}\n\nexport const gitAdapter: ForgeAdapter = {\n async clone(options: CloneOptions) {\n if (!(await hasCommand('git'))) {\n throw new Error(\n '`git` is not installed. Install it from https://git-scm.com/ and try again.'\n );\n }\n const url = buildCloneUrl(options);\n const { code } = await execInherit('git', ['clone', url, options.dest]);\n if (code !== 0) {\n throw new Error(`git clone exited with code ${code}`);\n }\n },\n\n async checkRemote(input: RemoteCheckInput): Promise<RemoteCheckResult> {\n if (!(await hasCommand('git'))) {\n return { state: 'unknown', reason: 'git not installed' };\n }\n // `git ls-remote` only proves reachability — it cannot detect a rename.\n // Force non-interactive SSH and a hard timeout so an unreachable or\n // auth-prompting host can't wedge the whole import.\n const url = input.originUrl ?? buildCloneUrl(input);\n const result = await execCapture('git', ['ls-remote', url], {\n timeoutMs: REMOTE_TIMEOUT_MS,\n env: {\n GIT_TERMINAL_PROMPT: '0',\n GIT_SSH_COMMAND: 'ssh -oBatchMode=yes -oConnectTimeout=5'\n }\n });\n if (result.timedOut) {\n return { state: 'unknown', reason: 'ls-remote timed out' };\n }\n if (result.code === 0) {\n return {\n state: 'exists',\n canonical: { owner: input.owner, repo: input.repo }\n };\n }\n // A failure is only `gone` when the host clearly says the repo is missing.\n // Unreachable hosts, auth failures, and the generic SSH error stay\n // `unknown` so we never falsely declare a repo deleted (the generic SSH\n // message even contains \"the repository exists\").\n if (isRepoMissing(result.stderr)) {\n return { state: 'gone' };\n }\n const reason =\n result.stderr\n .split('\\n')\n .map((line) => line.trim())\n .find(Boolean) ?? `git ls-remote exited with code ${result.code}`;\n return { state: 'unknown', reason };\n }\n};\n\n/** True only for an unambiguous \"this repository does not exist\" signal. */\nfunction isRepoMissing(stderr: string): boolean {\n const s = stderr.toLowerCase();\n return (\n /repository not found/.test(s) ||\n /remote:.*not found/.test(s) ||\n /\\b404\\b/.test(s) ||\n /could not find repository/.test(s)\n );\n}\n\n// Exported for testing.\nexport const __test = { buildCloneUrl, isRepoMissing };\n","/**\n * Map over `items` running at most `limit` calls of `fn` at once, preserving\n * input order in the result. Keeps `import` from spawning one subprocess per\n * repo all at once when checking remotes across a large tree.\n */\nexport async function mapLimit<T, R>(\n items: T[],\n limit: number,\n fn: (item: T, index: number) => Promise<R>\n): Promise<R[]> {\n const results: R[] = Array.from({ length: items.length });\n const max = Math.max(1, Math.min(limit, items.length));\n let next = 0;\n\n async function worker(): Promise<void> {\n while (next < items.length) {\n const index = next++;\n results[index] = await fn(items[index]!, index);\n }\n }\n\n await Promise.all(Array.from({ length: max }, () => worker()));\n return results;\n}\n","import { mapLimit } from '../utils/concurrency.ts';\nimport { execCapture, execInherit, hasCommand } from '../utils/exec.ts';\nimport type {\n CloneOptions,\n ForgeAdapter,\n RemoteCheckInput,\n RemoteCheckResult\n} from './types.ts';\n\nconst GRAPHQL_CHUNK = 100;\nconst FALLBACK_CONCURRENCY = 8;\nconst GH_TIMEOUT_MS = 20_000;\n\n/** Single-repo REST check. `gh api` follows the redirect a renamed/transferred\n * repo issues, so the returned full_name reveals the canonical owner/repo. */\nasync function checkOne(\n owner: string,\n repo: string\n): Promise<RemoteCheckResult> {\n const result = await execCapture(\n 'gh',\n ['api', `repos/${owner}/${repo}`, '--jq', '.full_name'],\n { timeoutMs: GH_TIMEOUT_MS }\n );\n if (result.timedOut) {\n return { state: 'unknown', reason: 'gh api timed out' };\n }\n if (result.code !== 0) {\n if (/404|not found/i.test(result.stderr)) return { state: 'gone' };\n return {\n state: 'unknown',\n reason: result.stderr.trim() || `gh api exited with code ${result.code}`\n };\n }\n const fullName = result.stdout.trim();\n const [canonicalOwner, canonicalRepo] = fullName.split('/');\n if (!canonicalOwner || !canonicalRepo) {\n return { state: 'unknown', reason: 'could not parse gh api full_name' };\n }\n const canonical = { owner: canonicalOwner, repo: canonicalRepo };\n if (canonicalOwner === owner && canonicalRepo === repo) {\n return { state: 'exists', canonical };\n }\n return {\n state: 'moved',\n canonical,\n canonicalUrl: `https://github.com/${canonicalOwner}/${canonicalRepo}.git`\n };\n}\n\nfunction buildQuery(chunk: RemoteCheckInput[]): string {\n const fields = chunk\n .map(\n (input, i) =>\n ` r${i}: repository(owner: ${JSON.stringify(input.owner)}, name: ${JSON.stringify(input.repo)}) { nameWithOwner }`\n )\n .join('\\n');\n return `query {\\n${fields}\\n}`;\n}\n\nexport const githubAdapter: ForgeAdapter = {\n async clone({ owner, repo, dest }: CloneOptions) {\n if (!(await hasCommand('gh'))) {\n throw new Error(\n 'GitHub CLI (`gh`) is not installed. Install it from https://cli.github.com/ and run `gh auth login`.'\n );\n }\n const { code } = await execInherit('gh', [\n 'repo',\n 'clone',\n `${owner}/${repo}`,\n dest\n ]);\n if (code !== 0) {\n throw new Error(`gh repo clone exited with code ${code}`);\n }\n },\n\n async checkRemote({\n owner,\n repo\n }: RemoteCheckInput): Promise<RemoteCheckResult> {\n if (!(await hasCommand('gh'))) {\n return { state: 'unknown', reason: 'gh not installed' };\n }\n return checkOne(owner, repo);\n },\n\n /**\n * One GraphQL request resolves up to GRAPHQL_CHUNK repos at once. GraphQL\n * does not follow rename redirects, so a hit means `exists`; a null/miss\n * could be either `gone` or `moved` and is disambiguated with a single\n * (redirect-following) REST call, run concurrency-limited.\n */\n async checkRemotes(inputs: RemoteCheckInput[]): Promise<RemoteCheckResult[]> {\n if (inputs.length === 0) return [];\n if (!(await hasCommand('gh'))) {\n return inputs.map(() => ({\n state: 'unknown',\n reason: 'gh not installed'\n }));\n }\n\n const results: (RemoteCheckResult | null)[] = Array.from(\n { length: inputs.length },\n () => null\n );\n\n for (let start = 0; start < inputs.length; start += GRAPHQL_CHUNK) {\n const chunk = inputs.slice(start, start + GRAPHQL_CHUNK);\n const res = await execCapture(\n 'gh',\n ['api', 'graphql', '-f', `query=${buildQuery(chunk)}`],\n { timeoutMs: GH_TIMEOUT_MS }\n );\n type GraphqlData = Record<string, { nameWithOwner?: string } | null>;\n let data: GraphqlData | null = null;\n try {\n data = (JSON.parse(res.stdout) as { data?: GraphqlData }).data ?? null;\n } catch {\n data = null;\n }\n for (let i = 0; i < chunk.length; i++) {\n const node = data?.[`r${i}`];\n if (node?.nameWithOwner) {\n const [owner, repo] = node.nameWithOwner.split('/');\n if (owner && repo) {\n results[start + i] = {\n state: 'exists',\n canonical: { owner, repo }\n };\n }\n }\n // Left null → resolved via REST fallback below.\n }\n }\n\n const pending = results.flatMap((r, i) => (r === null ? [i] : []));\n await mapLimit(pending, FALLBACK_CONCURRENCY, async (index) => {\n results[index] = await checkOne(\n inputs[index]!.owner,\n inputs[index]!.repo\n );\n });\n\n return results as RemoteCheckResult[];\n }\n};\n","import type { ForgeType } from '../config/schema.ts';\nimport { gitAdapter } from './git.ts';\nimport { githubAdapter } from './github.ts';\nimport type { ForgeAdapter } from './types.ts';\n\nexport function getForgeAdapter(type: ForgeType): ForgeAdapter {\n switch (type) {\n case 'github':\n return githubAdapter;\n case 'git':\n return gitAdapter;\n case 'gitlab':\n case 'gitea':\n case 'codeberg':\n throw new Error(\n `Forge type \"${type}\" is not implemented yet. Use type: 'git' for a vanilla git-clone fallback.`\n );\n default: {\n const exhaustive: never = type;\n throw new Error(`Unknown forge type: ${String(exhaustive)}`);\n }\n }\n}\n","export interface ParsedSlug {\n /** Forge alias if explicitly specified via `<forge>:<owner>/<repo>` */\n forgeName?: string;\n /** Host if extracted from URL/SSH form */\n host?: string;\n owner: string;\n repo: string;\n}\n\nconst SHORT_RE = /^([\\w.-]+)\\/([\\w.-]+)$/;\nconst NAMED_RE = /^([\\w.-]+):([\\w.-]+)\\/([\\w.-]+)$/;\nconst SSH_RE = /^git@([\\w.-]+):([\\w.-]+)\\/([\\w.-]+?)(?:\\.git)?$/;\n\nfunction stripGitSuffix(repo: string): string {\n return repo.endsWith('.git') ? repo.slice(0, -4) : repo;\n}\n\n/**\n * Whether the input is *shaped* like a strict slug. Every form\n * {@link parseSlug} accepts — `owner/repo`, `forge:owner/repo`, SSH and\n * URL — contains a `/`, so a bare term like `gild` can never be one and is\n * free to be treated as a fuzzy query instead.\n *\n * Shaped-like is deliberately not the same as valid: `foo/bar/baz` is shaped\n * like a slug, so it stays a hard parse error rather than silently degrading\n * into a fuzzy search for something the user clearly meant as a slug.\n */\nexport function looksLikeSlug(input: string): boolean {\n return input.trim().includes('/');\n}\n\nexport function parseSlug(input: string): ParsedSlug {\n const trimmed = input.trim();\n if (!trimmed) {\n throw new Error('Slug is empty');\n }\n\n // git@host:owner/repo(.git)\n const ssh = SSH_RE.exec(trimmed);\n if (ssh) {\n return {\n host: ssh[1],\n owner: ssh[2]!,\n repo: stripGitSuffix(ssh[3]!)\n };\n }\n\n // https://host/owner/repo(.git) or http://...\n if (/^https?:\\/\\//.test(trimmed)) {\n let url: URL;\n try {\n url = new URL(trimmed);\n } catch {\n throw new Error(`Invalid URL: ${trimmed}`);\n }\n const segments = url.pathname.split('/').filter(Boolean);\n if (segments.length < 2) {\n throw new Error(`URL must contain owner and repo: ${trimmed}`);\n }\n return {\n host: url.host,\n owner: segments[0]!,\n repo: stripGitSuffix(segments[1]!)\n };\n }\n\n // forge:owner/repo\n const named = NAMED_RE.exec(trimmed);\n if (named) {\n return {\n forgeName: named[1],\n owner: named[2]!,\n repo: stripGitSuffix(named[3]!)\n };\n }\n\n // owner/repo\n const short = SHORT_RE.exec(trimmed);\n if (short) {\n return {\n owner: short[1]!,\n repo: stripGitSuffix(short[2]!)\n };\n }\n\n throw new Error(`Unrecognized slug format: ${input}`);\n}\n","import { execCapture, type CaptureResult } from '../utils/exec.ts';\n\nexport interface RepoStatus {\n branch: string;\n /** No upstream configured for the current branch. */\n detached: boolean;\n dirty: boolean;\n ahead: number;\n behind: number;\n /** Entries on `refs/stash` — local work no other field reports. */\n stashes: number;\n lastCommit: { sha: string; relativeDate: string } | null;\n}\n\nasync function gitIn(cwd: string, args: string[]): Promise<CaptureResult> {\n return execCapture('git', args, { cwd });\n}\n\n/** Network git ops (fetch/pull) must never block: force non-interactive SSH\n * and a hard timeout so an unreachable or auth-prompting remote can't wedge\n * a whole `sync` run. */\nconst NETWORK_TIMEOUT_MS = 30_000;\n\nasync function gitNetwork(cwd: string, args: string[]): Promise<CaptureResult> {\n return execCapture('git', args, {\n cwd,\n timeoutMs: NETWORK_TIMEOUT_MS,\n env: {\n GIT_TERMINAL_PROMPT: '0',\n GIT_SSH_COMMAND: 'ssh -oBatchMode=yes -oConnectTimeout=5'\n }\n });\n}\n\nexport async function getRepoStatus(localPath: string): Promise<RepoStatus> {\n const status: RepoStatus = {\n branch: 'HEAD',\n detached: false,\n dirty: false,\n ahead: 0,\n behind: 0,\n stashes: 0,\n lastCommit: null\n };\n\n const branchResult = await gitIn(localPath, ['branch', '--show-current']);\n status.branch = branchResult.stdout.trim() || 'HEAD';\n status.detached = !status.branch || status.branch === 'HEAD';\n\n const porcelain = await gitIn(localPath, ['status', '--porcelain']);\n status.dirty = porcelain.stdout.trim().length > 0;\n\n status.stashes = await countStashes(localPath);\n\n // ahead/behind only meaningful with an upstream\n const aheadBehind = await gitIn(localPath, [\n 'rev-list',\n '--left-right',\n '--count',\n '@{u}...HEAD'\n ]);\n if (aheadBehind.code === 0) {\n const match = aheadBehind.stdout.trim().match(/^(\\d+)\\s+(\\d+)$/);\n if (match) {\n status.behind = Number(match[1]);\n status.ahead = Number(match[2]);\n }\n }\n\n const lastCommit = await gitIn(localPath, ['log', '-1', '--format=%h|%cr']);\n if (lastCommit.code === 0) {\n const [sha, relativeDate] = lastCommit.stdout.trim().split('|');\n if (sha && relativeDate) {\n status.lastCommit = { sha, relativeDate };\n }\n }\n\n return status;\n}\n\nexport async function fetchRepo(localPath: string): Promise<CaptureResult> {\n return gitNetwork(localPath, ['fetch', '--all', '--prune']);\n}\n\nexport async function pullRepo(localPath: string): Promise<CaptureResult> {\n return gitNetwork(localPath, ['pull', '--ff-only']);\n}\n\nexport async function isClean(localPath: string): Promise<boolean> {\n const result = await gitIn(localPath, ['status', '--porcelain']);\n return result.code === 0 && result.stdout.trim().length === 0;\n}\n\nexport interface GitRemote {\n name: string;\n url: string;\n}\n\n/** True if `localPath` is inside a git work tree. */\nexport async function isGitRepo(localPath: string): Promise<boolean> {\n const result = await gitIn(localPath, ['rev-parse', '--is-inside-work-tree']);\n return result.code === 0 && result.stdout.trim() === 'true';\n}\n\n/** The `origin` remote URL, or null when there is no `origin`. */\nexport async function getOriginUrl(localPath: string): Promise<string | null> {\n const result = await gitIn(localPath, ['remote', 'get-url', 'origin']);\n if (result.code !== 0) return null;\n const url = result.stdout.trim();\n return url.length > 0 ? url : null;\n}\n\n/** Every configured remote with a URL, in config order. */\nexport async function getRemotes(localPath: string): Promise<GitRemote[]> {\n const result = await gitIn(localPath, [\n 'config',\n '--get-regexp',\n '^remote\\\\..*\\\\.url$'\n ]);\n if (result.code !== 0) return [];\n const remotes: GitRemote[] = [];\n for (const line of result.stdout.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n const match = trimmed.match(/^remote\\.(.+)\\.url\\s+(.+)$/);\n if (match) remotes.push({ name: match[1]!, url: match[2]! });\n }\n return remotes;\n}\n\n/** Repoint `origin` at a new URL. Used by `import --fix`. */\nexport async function setOriginUrl(\n localPath: string,\n url: string\n): Promise<CaptureResult> {\n return gitIn(localPath, ['remote', 'set-url', 'origin', url]);\n}\n\n/** Unix timestamp (seconds) of the most recent commit on a LOCAL branch, or\n * null when there are no commits. Excludes remote-tracking refs on purpose:\n * a recent `fetch` must not make a long-idle local checkout look fresh.\n * Drives the staleness check in `cleanup`. */\nexport async function getLastCommitUnix(\n localPath: string\n): Promise<number | null> {\n const result = await gitIn(localPath, [\n 'log',\n '--branches',\n '-1',\n '--format=%ct'\n ]);\n if (result.code !== 0) return null;\n const ts = Number.parseInt(result.stdout.trim(), 10);\n return Number.isFinite(ts) ? ts : null;\n}\n\n/**\n * True when any commit on any local branch is not reachable from a remote\n * tracking ref — i.e. there is work that exists only locally. Conservative\n * by design: with no remotes configured, everything counts as unpushed.\n */\nexport async function hasUnpushedCommits(localPath: string): Promise<boolean> {\n const result = await gitIn(localPath, [\n 'log',\n '--branches',\n '--not',\n '--remotes',\n '--format=%H',\n '-1'\n ]);\n if (result.code !== 0) return true;\n return result.stdout.trim().length > 0;\n}\n\n/**\n * The local branches that carry commits existing on no remote — the concrete\n * work behind `hasUnpushedCommits`'s boolean. Reporting only: `delete` names\n * them so the user sees what a deletion would actually destroy, rather than\n * just being told \"unpushed commits\". Returns [] when nothing is unpushed or\n * the branch list cannot be read.\n */\nexport async function getUnpushedBranches(\n localPath: string\n): Promise<string[]> {\n const listed = await gitIn(localPath, [\n 'for-each-ref',\n '--format=%(refname:short)',\n 'refs/heads'\n ]);\n if (listed.code !== 0) return [];\n\n const branches = listed.stdout\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean);\n\n const unpushed: string[] = [];\n for (const branch of branches) {\n const result = await gitIn(localPath, [\n 'log',\n branch,\n '--not',\n '--remotes',\n '--format=%H',\n '-1'\n ]);\n if (result.code === 0 && result.stdout.trim().length > 0) {\n unpushed.push(branch);\n }\n }\n return unpushed;\n}\n\n/**\n * Number of entries on the stash. Stashed work is invisible to every other\n * local check: `git status --porcelain` reports no working-tree change once\n * the stash is taken, and stash commits live on `refs/stash`, so\n * `git log --branches` (staleness) and `--branches --not --remotes`\n * (unpushed) skip them too. A repo whose only local work is stashed therefore\n * looks clean, idle and fully pushed unless this is checked explicitly.\n *\n * `%gd` prints one bare `stash@{n}` per entry, so a stash message containing\n * a newline cannot inflate the count. Returns 0 when the stash is unreadable\n * (e.g. not a git repo) — callers gate on `isGitRepo` first.\n */\nexport async function countStashes(localPath: string): Promise<number> {\n const result = await gitIn(localPath, ['stash', 'list', '--format=%gd']);\n if (result.code !== 0) return 0;\n return result.stdout.split('\\n').filter((line) => line.trim().length > 0)\n .length;\n}\n\n/** True when the repo has any stashed work. See {@link countStashes}. */\nexport async function hasStashes(localPath: string): Promise<boolean> {\n return (await countStashes(localPath)) > 0;\n}\n","import { readdir, rmdir } from 'node:fs/promises';\nimport { join } from 'pathe';\nimport type { ForgeMapConfig, ForgeType } from '../config/schema.ts';\nimport { getForgeAdapter } from '../forges/registry.ts';\nimport type { RemoteCheckInput, RemoteCheckResult } from '../forges/types.ts';\nimport { parseSlug } from '../slug/parse.ts';\nimport { mapLimit } from '../utils/concurrency.ts';\nimport {\n getLastCommitUnix,\n getOriginUrl,\n getRepoStatus,\n hasUnpushedCommits,\n isGitRepo\n} from './git.ts';\nimport type { ScannedRepo } from './scan.ts';\n\nconst REMOTE_CONCURRENCY = 10;\n\n/**\n * A deletion candidate: a git repo that has an origin. `dirty` / `unpushed` /\n * `stashes` record its local state; the gates below decide whether those block\n * deletion (overridable via flags) while a missing remote is always a hard stop.\n * Carries the origin identity used for the remote-existence check.\n *\n * Shared by `cleanup` (bulk, staleness-driven) and `delete` (targeted) so the\n * two commands cannot drift apart on what counts as safe to remove.\n */\nexport interface RepoEvaluation {\n repo: ScannedRepo;\n origin: string;\n /** owner/repo parsed from origin (falls back to the folder identity). */\n owner: string;\n name: string;\n /** Newest commit on a local branch; null when the repo has no commits. */\n lastCommitUnix: number | null;\n dirty: boolean;\n unpushed: boolean;\n /** Entries on the stash; deleting the repo destroys them. */\n stashes: number;\n}\n\n/** A `RepoEvaluation` that passed a staleness cutoff, so its last commit is known. */\nexport interface StaleRepoEvaluation extends RepoEvaluation {\n lastCommitUnix: number;\n}\n\nexport interface EvaluateOptions {\n /**\n * Only return the repo when its newest local commit is at or before this\n * unix timestamp (and a repo with no commits at all is skipped). Omit to\n * evaluate regardless of age — `delete` targets one repo by name and has no\n * staleness requirement.\n */\n cutoffUnix?: number;\n}\n\nexport async function evaluateRepo(\n repo: ScannedRepo,\n options: { cutoffUnix: number }\n): Promise<StaleRepoEvaluation | null>;\nexport async function evaluateRepo(\n repo: ScannedRepo,\n options?: EvaluateOptions\n): Promise<RepoEvaluation | null>;\n/**\n * Local gates (no network). Returns null for repos we ignore entirely:\n * non-git dirs, repos without an origin, and — when `cutoffUnix` is given —\n * repos that are NOT stale (their newest local commit is within the cutoff).\n * Anything returned carries its dirty/unpushed/stashed state.\n */\nexport async function evaluateRepo(\n repo: ScannedRepo,\n options: EvaluateOptions = {}\n): Promise<RepoEvaluation | null> {\n if (!(await isGitRepo(repo.localPath))) return null;\n const origin = await getOriginUrl(repo.localPath);\n if (!origin) return null;\n\n const lastCommitUnix = await getLastCommitUnix(repo.localPath);\n if (options.cutoffUnix !== undefined) {\n if (lastCommitUnix === null || lastCommitUnix > options.cutoffUnix) {\n return null;\n }\n }\n\n const status = await getRepoStatus(repo.localPath);\n const dirty = status.dirty;\n const stashes = status.stashes;\n const unpushed = await hasUnpushedCommits(repo.localPath);\n\n let owner = repo.owner;\n let name = repo.repo;\n try {\n const parsed = parseSlug(origin);\n owner = parsed.owner;\n name = parsed.repo;\n } catch {\n // Unparseable origin — fall back to the folder identity.\n }\n\n return {\n repo,\n origin,\n owner,\n name,\n lastCommitUnix,\n dirty,\n unpushed,\n stashes\n };\n}\n\n/** Which local-work gates the caller has explicitly opted to override. */\nexport interface GateOverrides {\n includeDirty: boolean;\n includeUnpushed: boolean;\n includeStashed: boolean;\n}\n\nconst UNCOMMITTED = 'uncommitted changes';\nconst UNPUSHED = 'unpushed commits';\nconst STASHED = 'stashed work';\n\n/** Stashes are separate work, so `--include-dirty` must not override them. */\nfunction stashedReason(stashes: number): string {\n return `${STASHED} (${stashes} stash${stashes === 1 ? '' : 'es'})`;\n}\n\n/**\n * The flag that lets a caller override a local gate, or undefined for a gate\n * that cannot be overridden. Lives beside `localBlocker` so a gate and its\n * escape hatch cannot drift apart; `delete` reads it to tell the user which\n * flag would force the deletion through.\n *\n * A function rather than a lookup table because the stashed-work reason\n * carries its count, so it has no fixed key.\n */\nexport function localGateOverride(reason: string): string | undefined {\n if (reason === UNCOMMITTED) return '--include-dirty';\n if (reason === UNPUSHED) return '--include-unpushed';\n if (reason.startsWith(STASHED)) return '--include-stashed';\n return undefined;\n}\n\n/**\n * Why this repo must not be deleted on local grounds, or null when every\n * local gate passes. The single place `cleanup` and `delete` agree on what\n * counts as local work at risk — a new gate added here reaches both commands.\n */\nexport function localBlocker(\n evaluation: RepoEvaluation,\n overrides: GateOverrides\n): string | null {\n if (evaluation.dirty && !overrides.includeDirty) return UNCOMMITTED;\n if (evaluation.unpushed && !overrides.includeUnpushed) return UNPUSHED;\n if (evaluation.stashes > 0 && !overrides.includeStashed) {\n return stashedReason(evaluation.stashes);\n }\n return null;\n}\n\n/**\n * Why the remote's state forbids deletion, or null when it is safe. A remote\n * that is gone or unreachable is ALWAYS a hard stop — no flag overrides it,\n * because the local copy may be the last one in existence.\n */\nexport function remoteBlocker(\n state: RemoteCheckResult['state'] | undefined\n): string | null {\n if (state === 'exists' || state === 'moved') return null;\n return state === 'gone' ? 'remote no longer exists' : 'remote unreachable';\n}\n\n/** Check each candidate's remote, grouped by forge so GitHub can batch. */\nexport async function classifyRemotes(\n candidates: RepoEvaluation[]\n): Promise<Map<string, RemoteCheckResult>> {\n const byType = new Map<ForgeType, RepoEvaluation[]>();\n for (const c of candidates) {\n const list = byType.get(c.repo.forge.type);\n if (list) list.push(c);\n else byType.set(c.repo.forge.type, [c]);\n }\n\n const results = new Map<string, RemoteCheckResult>();\n await Promise.all(\n Array.from(byType, async ([type, items]) => {\n const inputs: RemoteCheckInput[] = items.map((c) => ({\n forge: c.repo.forge,\n owner: c.owner,\n repo: c.name,\n originUrl: c.origin\n }));\n\n let adapter: ReturnType<typeof getForgeAdapter>;\n try {\n adapter = getForgeAdapter(type);\n } catch (error) {\n for (const c of items) {\n results.set(c.repo.localPath, {\n state: 'unknown',\n reason: (error as Error).message\n });\n }\n return;\n }\n\n let res: RemoteCheckResult[];\n if (adapter.checkRemotes) {\n try {\n res = await adapter.checkRemotes(inputs);\n } catch (error) {\n res = inputs.map(() => ({\n state: 'unknown',\n reason: (error as Error).message\n }));\n }\n } else if (adapter.checkRemote) {\n const check = adapter.checkRemote;\n res = await mapLimit(inputs, REMOTE_CONCURRENCY, async (inp) => {\n try {\n return await check(inp);\n } catch (error) {\n return { state: 'unknown', reason: (error as Error).message };\n }\n });\n } else {\n res = inputs.map(() => ({\n state: 'unknown',\n reason: `${type} has no remote check`\n }));\n }\n\n items.forEach((c, i) => results.set(c.repo.localPath, res[i]!));\n })\n );\n\n return results;\n}\n\nasync function safeReaddir(path: string): Promise<string[] | null> {\n try {\n return await readdir(path);\n } catch {\n return null;\n }\n}\n\n/** Empty owner directories (and a server directory that holds only such empty\n * owners) under the configured forge dirs. Detection only — no removal. */\nexport async function findEmptyDirs(\n root: string,\n config: ForgeMapConfig\n): Promise<string[]> {\n const empties: string[] = [];\n for (const forge of Object.values(config.forges)) {\n const serverPath = join(root, forge.dir);\n const owners = await safeReaddir(serverPath);\n if (owners === null) continue;\n let emptyCount = 0;\n for (const owner of owners) {\n const ownerPath = join(serverPath, owner);\n const inner = await safeReaddir(ownerPath);\n if (inner !== null && inner.length === 0) {\n empties.push(ownerPath);\n emptyCount++;\n }\n }\n // The server dir itself goes if it is empty or holds only empty owners.\n if (owners.length === 0 || emptyCount === owners.length) {\n empties.push(serverPath);\n }\n }\n return empties;\n}\n\n/** Remove the dirs from findEmptyDirs (owners before server dirs). */\nexport async function pruneEmptyDirs(\n root: string,\n config: ForgeMapConfig\n): Promise<number> {\n const empties = await findEmptyDirs(root, config);\n let removed = 0;\n for (const dir of empties) {\n try {\n await rmdir(dir);\n removed++;\n } catch {\n // Not actually empty (a file slipped in) — leave it.\n }\n }\n return removed;\n}\n","import { rm } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors } from 'consola/utils';\nimport { dirname } from 'pathe';\nimport { resolveRoot } from '../utils/path.ts';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { removeCachedRepo, scanReposCached } from '../repos/cache.ts';\nimport {\n classifyRemotes,\n evaluateRepo,\n findEmptyDirs,\n localBlocker,\n pruneEmptyDirs,\n remoteBlocker,\n type StaleRepoEvaluation\n} from '../repos/evaluate.ts';\nimport { mapLimit } from '../utils/concurrency.ts';\n\nconst DAY_SECONDS = 86_400;\nconst LOCAL_CONCURRENCY = 16;\n\nfunction ageDays(lastCommitUnix: number): number {\n return Math.floor(\n Date.now() / 1000 / DAY_SECONDS - lastCommitUnix / DAY_SECONDS\n );\n}\n\nexport const cleanupCommand = defineCommand({\n meta: {\n name: 'cleanup',\n description:\n 'List stale, clean, fully-pushed repos whose remote still exists, then delete them locally after confirmation'\n },\n args: {\n days: {\n type: 'string',\n description: 'Minimum age in days since the last commit (default 365)',\n default: '365'\n },\n forge: {\n type: 'string',\n description: 'Restrict to a single forge alias'\n },\n 'dry-run': {\n type: 'boolean',\n description: 'Only list candidates; never prompt or delete',\n default: false\n },\n yes: {\n type: 'boolean',\n description: 'Skip the interactive confirmation (deletes immediately)',\n default: false\n },\n 'include-dirty': {\n type: 'boolean',\n description:\n 'Also delete repos with uncommitted changes (those changes are lost)',\n default: false\n },\n 'include-unpushed': {\n type: 'boolean',\n description:\n 'Also delete repos with unpushed commits (those commits are lost)',\n default: false\n },\n 'include-stashed': {\n type: 'boolean',\n description: 'Also delete repos with stashed work (that stash is lost)',\n default: false\n },\n cache: {\n type: 'boolean',\n description: 'Use the scanned-repos cache',\n negativeDescription: 'Skip the scanned-repos cache',\n default: true\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const days = Number.parseInt(args.days, 10);\n if (!Number.isFinite(days) || days < 0) {\n consola.error(`Invalid --days value \"${args.days}\".`);\n process.exitCode = 1;\n return;\n }\n\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n let repos = await scanReposCached({\n config: loaded.config,\n configDir,\n useCache: args.cache\n });\n if (args.forge) repos = repos.filter((r) => r.forgeName === args.forge);\n\n const cutoffUnix = Math.floor(Date.now() / 1000) - days * DAY_SECONDS;\n\n // Stale repos that have an origin. (Recent repos and repos without an\n // origin are ignored entirely and never listed.)\n const stale = (\n await mapLimit(repos, LOCAL_CONCURRENCY, (repo) =>\n evaluateRepo(repo, { cutoffUnix })\n )\n ).filter((c): c is StaleRepoEvaluation => c !== null);\n\n const includeDirty = Boolean(args['include-dirty']);\n const includeUnpushed = Boolean(args['include-unpushed']);\n const includeStashed = Boolean(args['include-stashed']);\n const overrides = { includeDirty, includeUnpushed, includeStashed };\n\n // Dirty / unpushed / stashed only block when the matching --include flag\n // is off. A missing remote is ALWAYS a hard stop (never overridable). So\n // only the locally-eligible repos need a remote check.\n const remoteStates = await classifyRemotes(\n stale.filter((c) => localBlocker(c, overrides) === null)\n );\n\n const candidates: StaleRepoEvaluation[] = [];\n const kept: Array<{ repo: StaleRepoEvaluation; reason: string }> = [];\n for (const c of stale) {\n const reason =\n localBlocker(c, overrides) ??\n remoteBlocker(remoteStates.get(c.repo.localPath)?.state);\n if (reason === null) candidates.push(c);\n else kept.push({ repo: c, reason });\n }\n candidates.sort((a, b) => a.lastCommitUnix - b.lastCommitUnix);\n kept.sort((a, b) => a.repo.lastCommitUnix - b.repo.lastCommitUnix);\n\n if (candidates.length > 0) {\n process.stdout.write(\n `${colors.bold(`${candidates.length} repo(s) eligible for cleanup`)} ${colors.dim(`(idle ${days}+ days, remote exists)`)}\\n\\n`\n );\n for (const c of candidates) {\n const flags = [\n c.dirty ? colors.red('dirty') : '',\n c.unpushed ? colors.red('unpushed') : '',\n c.stashes > 0 ? colors.red(`stashed:${c.stashes}`) : ''\n ]\n .filter(Boolean)\n .join(' ');\n process.stdout.write(\n ` ${colors.cyan(`${c.repo.forgeName}:${c.repo.slug}`)} ${colors.dim(`${ageDays(c.lastCommitUnix)}d idle`)}${flags ? ` ${flags}` : ''} ${colors.dim(c.repo.localPath)}\\n`\n );\n }\n process.stdout.write('\\n');\n }\n\n // Explain why the other idle repos were spared.\n if (kept.length > 0) {\n process.stdout.write(\n `${colors.dim(`${kept.length} idle repo(s) kept (not safe to delete):`)}\\n`\n );\n for (const k of kept) {\n process.stdout.write(\n ` ${colors.dim(`${k.repo.repo.forgeName}:${k.repo.repo.slug} ${ageDays(k.repo.lastCommitUnix)}d idle — ${k.reason}`)}\\n`\n );\n }\n process.stdout.write('\\n');\n }\n\n const root = resolveRoot(loaded.config.root, configDir);\n\n // Empty owner/server directories (e.g. left behind by earlier deletions)\n // are tidied on every run — they hold no files, so this is non-destructive.\n if (args['dry-run']) {\n const empties = await findEmptyDirs(root, loaded.config);\n if (empties.length > 0) {\n process.stdout.write(\n `${colors.dim(`${empties.length} empty folder(s) would be removed:`)}\\n`\n );\n for (const e of empties) {\n process.stdout.write(` ${colors.dim(e)}\\n`);\n }\n process.stdout.write('\\n');\n }\n consola.info(\n candidates.length > 0\n ? 'Dry run — nothing deleted.'\n : 'Nothing to delete.'\n );\n return;\n }\n\n if (candidates.length > 0) {\n // Loud warning when --include flags put real work on the chopping block.\n const losing = candidates.filter(\n (c) => c.dirty || c.unpushed || c.stashes > 0\n ).length;\n if (losing > 0) {\n consola.warn(\n `${losing} of these have uncommitted/unpushed/stashed work that will be permanently lost.`\n );\n }\n\n let confirmed = args.yes;\n if (!confirmed) {\n const answer = await consola.prompt(\n `Type \"yes\" to delete these ${candidates.length} repo(s) locally:`,\n { type: 'text', cancel: 'null' }\n );\n confirmed = typeof answer === 'string' && answer.trim() === 'yes';\n }\n if (!confirmed) {\n consola.info('Aborted — nothing deleted.');\n return;\n }\n\n for (const c of candidates) {\n await rm(c.repo.localPath, { recursive: true, force: true });\n await removeCachedRepo(\n { config: loaded.config, configDir },\n c.repo.localPath\n );\n consola.success(`Deleted ${c.repo.localPath}`);\n }\n consola.success(`Removed ${candidates.length} repo(s).`);\n }\n\n // Sweep empty owner/server dirs (pre-existing + newly emptied by deletes).\n const emptied = await pruneEmptyDirs(root, loaded.config);\n if (emptied > 0) {\n consola.success(`Removed ${emptied} empty folder(s).`);\n } else if (candidates.length === 0) {\n consola.info('Nothing to clean up.');\n }\n }\n});\n","import { join } from 'pathe';\nimport type { ForgeConfig, ForgeMapConfig } from '../config/schema.ts';\nimport { resolveRoot } from '../utils/path.ts';\nimport type { ParsedSlug } from './parse.ts';\n\nexport interface ResolvedSlug {\n forgeName: string;\n forge: ForgeConfig;\n owner: string;\n repo: string;\n localPath: string;\n}\n\nexport interface ResolveOptions {\n config: ForgeMapConfig;\n configDir: string;\n}\n\nfunction findForgeByHost(\n forges: ForgeMapConfig['forges'],\n host: string\n): { name: string; forge: ForgeConfig } | undefined {\n for (const [name, forge] of Object.entries(forges)) {\n if (forge.host.toLowerCase() === host.toLowerCase()) {\n return { name, forge };\n }\n }\n return undefined;\n}\n\nexport function resolveSlug(\n parsed: ParsedSlug,\n options: ResolveOptions\n): ResolvedSlug {\n const { config, configDir } = options;\n\n let forgeName: string;\n let forge: ForgeConfig;\n\n if (parsed.forgeName) {\n const candidate = config.forges[parsed.forgeName];\n if (!candidate) {\n throw new Error(\n `Forge \"${parsed.forgeName}\" is not defined in forgemap.config`\n );\n }\n forgeName = parsed.forgeName;\n forge = candidate;\n } else if (parsed.host) {\n const match = findForgeByHost(config.forges, parsed.host);\n if (!match) {\n throw new Error(\n `No forge configured for host \"${parsed.host}\". Add it to forgemap.config.ts.`\n );\n }\n forgeName = match.name;\n forge = match.forge;\n } else {\n const candidate = config.forges[config.defaultForge];\n if (!candidate) {\n throw new Error(\n `Default forge \"${config.defaultForge}\" is not defined in forgemap.config`\n );\n }\n forgeName = config.defaultForge;\n forge = candidate;\n }\n\n const root = resolveRoot(config.root, configDir);\n const localPath = join(root, forge.dir, parsed.owner, parsed.repo);\n\n return {\n forgeName,\n forge,\n owner: parsed.owner,\n repo: parsed.repo,\n localPath\n };\n}\n","import { existsSync } from 'node:fs';\nimport { mkdir } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport type { GitProtocol } from '../config/schema.ts';\nimport { getForgeAdapter } from '../forges/registry.ts';\nimport { appendCachedRepo } from '../repos/cache.ts';\nimport { parseSlug } from '../slug/parse.ts';\nimport { resolveSlug } from '../slug/resolve.ts';\n\nexport const cloneCommand = defineCommand({\n meta: {\n name: 'clone',\n description: 'Clone a repo into the configured local layout'\n },\n args: {\n slug: {\n type: 'positional',\n description: 'owner/repo, forge:owner/repo, or full URL',\n required: true\n },\n ssh: {\n type: 'boolean',\n description: 'Force the SSH URL form (git-type forges only)',\n default: false\n },\n https: {\n type: 'boolean',\n description: 'Force the HTTPS URL form (git-type forges only)',\n default: false\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n if (args.ssh && args.https) {\n consola.error('--ssh and --https are mutually exclusive.');\n process.exitCode = 1;\n return;\n }\n\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const parsed = parseSlug(args.slug);\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const resolved = resolveSlug(parsed, {\n config: loaded.config,\n configDir\n });\n\n let protocol: GitProtocol | undefined;\n if (args.ssh) protocol = 'ssh';\n else if (args.https) protocol = 'https';\n\n if (protocol && resolved.forge.type !== 'git') {\n consola.warn(\n `--${protocol} is ignored for type \"${resolved.forge.type}\" — the adapter selects the URL itself.`\n );\n protocol = undefined;\n }\n\n if (existsSync(resolved.localPath)) {\n consola.info(`Already cloned at ${resolved.localPath}`);\n return;\n }\n\n await mkdir(dirname(resolved.localPath), { recursive: true });\n\n const adapter = getForgeAdapter(resolved.forge.type);\n await adapter.clone({\n forge: resolved.forge,\n owner: resolved.owner,\n repo: resolved.repo,\n dest: resolved.localPath,\n protocol\n });\n\n // Keep the scan cache hot so the next `list`/`cd`/`status` doesn't\n // pay for an invalidation walk just because we added one repo.\n await appendCachedRepo(\n { config: loaded.config, configDir },\n {\n forgeName: resolved.forgeName,\n forge: resolved.forge,\n owner: resolved.owner,\n repo: resolved.repo,\n localPath: resolved.localPath,\n slug: `${resolved.owner}/${resolved.repo}`\n }\n );\n\n consola.success(\n `Cloned ${resolved.owner}/${resolved.repo} → ${resolved.localPath}`\n );\n }\n});\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'pathe';\n\nexport type Shell = 'zsh' | 'bash' | 'fish';\n\nexport const SUPPORTED_SHELLS: Shell[] = ['zsh', 'bash', 'fish'];\n\nexport function detectShell(): Shell {\n const env = process.env.SHELL ?? '';\n if (env.endsWith('/fish')) return 'fish';\n if (env.endsWith('/bash')) return 'bash';\n return 'zsh';\n}\n\nexport function rcFileFor(shell: Shell): string {\n const home = homedir();\n if (shell === 'fish') return join(home, '.config', 'fish', 'config.fish');\n if (shell === 'bash') return join(home, '.bashrc');\n return join(home, '.zshrc');\n}\n\nexport type InstallResult =\n | { status: 'installed'; rcFile: string }\n | { status: 'updated'; rcFile: string }\n | { status: 'present'; rcFile: string };\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** Strip every marker-guarded block for any of `labels` from `content`. */\nfunction stripBlocks(content: string, labels: string[]): string {\n let out = content;\n for (const label of labels) {\n const l = escapeRegExp(label);\n const re = new RegExp(\n `\\\\n*# >>> forgemap ${l} >>>[\\\\s\\\\S]*?# <<< forgemap ${l} <<<\\\\n?`,\n 'g'\n );\n out = out.replace(re, '');\n }\n return out;\n}\n\n/**\n * Install a marker-guarded block of lines into the shell's rc file. `label`\n * namespaces the markers so independent features don't clash; `legacyLabels`\n * are older labels this feature used to write — they're removed too, so a\n * label rename never leaves a stale duplicate behind. Idempotent: re-running\n * collapses any existing/legacy blocks into a single current one.\n */\nexport async function installRcBlock(\n shell: Shell,\n label: string,\n lines: string[],\n legacyLabels: string[] = []\n): Promise<InstallResult> {\n const rcFile = rcFileFor(shell);\n let existing = '';\n try {\n existing = await readFile(rcFile, 'utf8');\n } catch {\n // rc file doesn't exist yet — we'll create it.\n }\n\n const allLabels = [label, ...legacyLabels];\n const hadAny = allLabels.some((l) =>\n existing.includes(`# >>> forgemap ${l} >>>`)\n );\n\n const block = `# >>> forgemap ${label} >>>\\n${lines.join('\\n')}\\n# <<< forgemap ${label} <<<\\n`;\n const cleaned = stripBlocks(existing, allLabels).replace(/\\s*$/, '');\n const next = cleaned.length > 0 ? `${cleaned}\\n\\n${block}` : block;\n\n if (next === existing) {\n return { status: 'present', rcFile };\n }\n await mkdir(dirname(rcFile), { recursive: true });\n await writeFile(rcFile, next, 'utf8');\n return { status: hadAny ? 'updated' : 'installed', rcFile };\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'pathe';\nimport type { ForgeConfig, ForgeMapConfig } from './schema.ts';\n\nconst HEADER = `/**\n * forgemap configuration.\n *\n * For type-safe authoring, install forgemap and switch to:\n * import { defineForgeMapConfig } from 'forgemap/config';\n * export default defineForgeMapConfig({ ... });\n *\n * @type {import('forgemap').ForgeMapUserConfig}\n */`;\n\n/** Quote a forge key unless it's already a bare JS identifier. */\nfunction quoteKey(name: string): string {\n return /^[A-Za-z_$][\\w$]*$/.test(name) ? name : `'${name}'`;\n}\n\nfunction renderForge(forge: ForgeConfig): string {\n const lines = [\n ` type: '${forge.type}',`,\n ` host: '${forge.host}',`,\n ` dir: '${forge.dir}'`\n ];\n if (forge.type === 'git' && forge.protocol) {\n lines.splice(1, 0, ` protocol: '${forge.protocol}',`);\n }\n return `{\\n${lines.join('\\n')}\\n }`;\n}\n\n/** Serialize a config to a `forgemap.config.ts` module body. */\nexport function renderConfigModule(config: ForgeMapConfig): string {\n const forgeEntries = Object.entries(config.forges)\n .map(([name, forge]) => ` ${quoteKey(name)}: ${renderForge(forge)}`)\n .join(',\\n');\n return `${HEADER}\nexport default {\n root: '${config.root}',\n defaultForge: '${config.defaultForge}',\n forges: {\n${forgeEntries}\n }\n};\n`;\n}\n\nexport interface WriteConfigOptions {\n outDir: string;\n force?: boolean;\n}\n\n/** Write a `forgemap.config.ts` into `outDir`. Returns null when the file\n * already exists and `force` is not set (the caller decides how to report). */\nexport async function writeConfigFile(\n config: ForgeMapConfig,\n options: WriteConfigOptions\n): Promise<{ path: string } | null> {\n const outDir = resolve(process.cwd(), options.outDir);\n const target = join(outDir, 'forgemap.config.ts');\n await mkdir(dirname(target), { recursive: true });\n try {\n await writeFile(target, renderConfigModule(config), {\n encoding: 'utf8',\n flag: options.force ? 'w' : 'wx'\n });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'EEXIST') {\n return null;\n }\n throw error;\n }\n return { path: target };\n}\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { join, resolve } from 'pathe';\nimport type { ForgeMapConfig } from '../../config/schema.ts';\nimport { writeConfigFile } from '../../config/write.ts';\n\nconst DEFAULT_CONFIG: ForgeMapConfig = {\n root: '.',\n defaultForge: 'github',\n forges: {\n github: {\n type: 'github',\n host: 'github.com',\n dir: 'comGithub'\n }\n }\n};\n\nexport const configInitCommand = defineCommand({\n meta: {\n name: 'init',\n description:\n 'Create a forgemap.config.ts in the current (or given) directory'\n },\n args: {\n out: {\n type: 'string',\n description: 'Directory to write forgemap.config.ts into',\n default: '.'\n },\n force: {\n type: 'boolean',\n description: 'Overwrite if forgemap.config.ts already exists',\n default: false\n }\n },\n async run({ args }) {\n const result = await writeConfigFile(DEFAULT_CONFIG, {\n outDir: args.out,\n force: args.force\n });\n\n if (!result) {\n const target = join(\n resolve(process.cwd(), args.out),\n 'forgemap.config.ts'\n );\n consola.error(`${target} already exists. Use --force to overwrite.`);\n process.exitCode = 1;\n return;\n }\n\n consola.success(`Wrote ${result.path}`);\n }\n});\n","import { defineCommand } from 'citty';\nimport { loadForgeMapConfig } from '../../config/load.ts';\n\nexport const configShowCommand = defineCommand({\n meta: {\n name: 'show',\n description: 'Print the resolved forgemap config and its source path'\n },\n args: {\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n process.stdout.write(\n JSON.stringify(\n {\n configFile: loaded.configFile ?? null,\n cwd: loaded.cwd,\n config: loaded.config\n },\n null,\n 2\n ) + '\\n'\n );\n }\n});\n","import { defineCommand } from 'citty';\nimport { configInitCommand } from './init.ts';\nimport { configShowCommand } from './show.ts';\n\nexport const configCommand = defineCommand({\n meta: {\n name: 'config',\n description: 'Manage the forgemap config file'\n },\n subCommands: {\n init: configInitCommand,\n show: configShowCommand\n }\n});\n","import { existsSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors } from 'consola/utils';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { removeCachedRepo } from '../repos/cache.ts';\nimport {\n classifyRemotes,\n evaluateRepo,\n localBlocker,\n localGateOverride,\n pruneEmptyDirs,\n remoteBlocker\n} from '../repos/evaluate.ts';\nimport { getUnpushedBranches } from '../repos/git.ts';\nimport type { ScannedRepo } from '../repos/scan.ts';\nimport { parseSlug } from '../slug/parse.ts';\nimport { resolveSlug } from '../slug/resolve.ts';\nimport { resolveRoot } from '../utils/path.ts';\n\nexport const deleteCommand = defineCommand({\n meta: {\n name: 'delete',\n description:\n 'Delete one local repo by slug, behind the same safety gates as cleanup (no staleness requirement)'\n },\n args: {\n slug: {\n type: 'positional',\n description: 'owner/repo, forge:owner/repo, or full URL',\n required: true\n },\n 'dry-run': {\n type: 'boolean',\n description: 'Only report what would happen; never prompt or delete',\n default: false\n },\n yes: {\n type: 'boolean',\n description: 'Skip the interactive confirmation (deletes immediately)',\n default: false\n },\n 'include-dirty': {\n type: 'boolean',\n description:\n 'Also delete when there are uncommitted changes (those changes are lost)',\n default: false\n },\n 'include-unpushed': {\n type: 'boolean',\n description:\n 'Also delete when there are unpushed commits (those commits are lost)',\n default: false\n },\n 'include-stashed': {\n type: 'boolean',\n description:\n 'Also delete when there is stashed work (that stash is lost)',\n default: false\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n\n // Resolve the slug straight to a path: `delete` targets one repo by name,\n // so it never scans (and therefore never writes the scan cache).\n let resolved: ReturnType<typeof resolveSlug>;\n try {\n resolved = resolveSlug(parseSlug(args.slug), {\n config: loaded.config,\n configDir\n });\n } catch (error) {\n consola.error((error as Error).message);\n process.exitCode = 1;\n return;\n }\n\n const repo: ScannedRepo = {\n forgeName: resolved.forgeName,\n forge: resolved.forge,\n owner: resolved.owner,\n repo: resolved.repo,\n localPath: resolved.localPath,\n slug: `${resolved.owner}/${resolved.repo}`\n };\n\n if (!existsSync(repo.localPath)) {\n consola.error(\n `No local repo at ${repo.localPath} — nothing to delete for ${repo.forgeName}:${repo.slug}.`\n );\n process.exitCode = 1;\n return;\n }\n\n // Not a git repo, or a git repo with no origin: forgemap cannot prove the\n // contents exist anywhere else, so it will not remove them.\n const evaluation = await evaluateRepo(repo);\n if (!evaluation) {\n consola.error(\n `Refusing to delete ${colors.cyan(`${repo.forgeName}:${repo.slug}`)} — ${repo.localPath} is not a git repo with an \"origin\" remote, so there is no remote copy to fall back on. Remove it by hand if you are sure.`\n );\n process.exitCode = 1;\n return;\n }\n\n process.stdout.write(\n `${colors.bold(`${repo.forgeName}:${repo.slug}`)} ${colors.dim(repo.localPath)}\\n`\n );\n\n // Name the local-only work rather than reporting a bare boolean, so the\n // user can see exactly what deleting this repo would destroy.\n const unpushedBranches = evaluation.unpushed\n ? await getUnpushedBranches(repo.localPath)\n : [];\n const losses: string[] = [];\n if (evaluation.dirty) losses.push('uncommitted changes');\n if (evaluation.unpushed) {\n losses.push(\n unpushedBranches.length > 0\n ? `unpushed commits on ${unpushedBranches.join(', ')}`\n : 'unpushed commits'\n );\n }\n if (evaluation.stashes > 0) {\n losses.push(\n `${evaluation.stashes} stash${evaluation.stashes === 1 ? '' : 'es'}`\n );\n }\n if (losses.length > 0) {\n process.stdout.write(\n ` ${colors.red('local-only work:')} ${losses.join('; ')}\\n`\n );\n }\n process.stdout.write('\\n');\n\n // A gone/unreachable remote is checked and reported first: it is the one\n // gate no flag can override, so nothing else about the repo matters.\n const remoteStates = await classifyRemotes([evaluation]);\n const remoteReason = remoteBlocker(remoteStates.get(repo.localPath)?.state);\n if (remoteReason) {\n consola.error(\n `Refusing to delete — ${remoteReason}. This is never overridable: the local copy may be the only one left.`\n );\n process.exitCode = 1;\n return;\n }\n\n const localReason = localBlocker(evaluation, {\n includeDirty: Boolean(args['include-dirty']),\n includeUnpushed: Boolean(args['include-unpushed']),\n includeStashed: Boolean(args['include-stashed'])\n });\n if (localReason) {\n const hint = localGateOverride(localReason);\n consola.error(\n `Refusing to delete — ${localReason}${hint ? `. Pass ${hint} to delete anyway (that work is lost)` : ''}.`\n );\n process.exitCode = 1;\n return;\n }\n\n if (args['dry-run']) {\n consola.info('Dry run — nothing deleted.');\n return;\n }\n\n if (losses.length > 0) {\n consola.warn(\n `This repo has local-only work that will be permanently lost: ${losses.join('; ')}.`\n );\n }\n\n // Deletion always requires the literal \"yes\"; --yes is the only bypass.\n let confirmed = args.yes;\n if (!confirmed) {\n const answer = await consola.prompt(\n `Type \"yes\" to delete ${repo.slug} locally:`,\n { type: 'text', cancel: 'null' }\n );\n confirmed = typeof answer === 'string' && answer.trim() === 'yes';\n }\n if (!confirmed) {\n consola.info('Aborted — nothing deleted.');\n return;\n }\n\n await rm(repo.localPath, { recursive: true, force: true });\n await removeCachedRepo(\n { config: loaded.config, configDir },\n repo.localPath\n );\n consola.success(`Deleted ${repo.localPath}`);\n\n const root = resolveRoot(loaded.config.root, configDir);\n const emptied = await pruneEmptyDirs(root, loaded.config);\n if (emptied > 0) {\n consola.success(`Removed ${emptied} empty folder(s).`);\n }\n }\n});\n","import type {\n ForgeConfig,\n ForgeType,\n GitForgeConfig,\n GitProtocol\n} from './schema.ts';\n\n/** Every forge `type` the config schema accepts, in prompt/display order. */\nexport const FORGE_TYPES: readonly ForgeType[] = [\n 'github',\n 'gitlab',\n 'gitea',\n 'codeberg',\n 'git'\n];\n\n/** Canonical host per forge type, offered as the host prompt's default. The\n * self-hosted flavors (`gitea`, plain `git`) have no universal host, so none\n * is suggested for them. */\nexport const DEFAULT_HOSTS: Partial<Record<ForgeType, string>> = {\n github: 'github.com',\n gitlab: 'gitlab.com',\n codeberg: 'codeberg.org'\n};\n\n/** Git clone protocols, in prompt order (`ssh` is the schema default). */\nexport const GIT_PROTOCOLS: readonly GitProtocol[] = ['ssh', 'https'];\n\nexport interface ForgeInput {\n type: ForgeType;\n host: string;\n dir: string;\n /** Only meaningful for `type: 'git'`. `ssh` is the schema default and is\n * dropped from the written config to keep it minimal — see {@link buildForge}. */\n protocol?: GitProtocol;\n}\n\n/**\n * A structurally-loose view of the config used by the in-place mutators below.\n * They run against both plain objects (the create path and unit tests) and\n * magicast proxies (round-trip writes), and the discriminated {@link ForgeConfig}\n * union is too strict to mutate field-by-field — so forges are treated as a flat\n * mutable record here.\n */\nexport interface MutableForge {\n type: ForgeType;\n host: string;\n dir: string;\n protocol?: GitProtocol;\n}\n\nexport interface EditableConfig {\n root?: string;\n defaultForge?: string;\n forges?: Record<string, MutableForge>;\n}\n\n/** Reject empty / whitespace-only keys; any other string is a valid map key.\n * Returns an error message, or `null` when the key is acceptable. */\nexport function validateForgeKey(raw: string): string | null {\n if (raw.trim().length === 0) return 'Forge key must not be empty.';\n return null;\n}\n\n/** Whether `value` is one of the schema's forge types (narrows a raw flag). */\nexport function isForgeType(value: string): value is ForgeType {\n return (FORGE_TYPES as readonly string[]).includes(value);\n}\n\n/** Whether `value` is a supported git protocol. */\nexport function isGitProtocol(value: string): value is GitProtocol {\n return (GIT_PROTOCOLS as readonly string[]).includes(value);\n}\n\n/** Build a `ForgeConfig` from collected input, keeping `protocol` only when it\n * is the non-default (`https`) git protocol. */\nexport function buildForge(input: ForgeInput): ForgeConfig {\n if (input.type === 'git') {\n const forge: GitForgeConfig = {\n type: 'git',\n host: input.host,\n dir: input.dir\n };\n if (input.protocol === 'https') forge.protocol = 'https';\n return forge;\n }\n // The non-git members are each just `BaseForgeConfig` with a fixed `type`; a\n // union-typed `type` field can't be expressed as an object literal, so assert\n // the shape (the `type` value is already narrowed to a non-git literal here).\n return { type: input.type, host: input.host, dir: input.dir } as ForgeConfig;\n}\n\nexport function addForge(\n config: EditableConfig,\n key: string,\n forge: MutableForge\n): void {\n if (!config.forges) config.forges = {};\n config.forges[key] = forge;\n}\n\nexport function removeForge(config: EditableConfig, key: string): void {\n if (config.forges) delete config.forges[key];\n}\n\nexport function setDefaultForge(config: EditableConfig, key: string): void {\n config.defaultForge = key;\n}\n\nexport interface ForgePatch {\n type?: ForgeType;\n host?: string;\n dir?: string;\n /** `null` clears the protocol; `undefined` leaves it untouched. */\n protocol?: GitProtocol | null;\n}\n\n/** Apply a partial change to an existing forge in place. Clears `protocol`\n * whenever the resulting type is not `git`, since it is meaningless there. */\nexport function editForge(\n config: EditableConfig,\n key: string,\n patch: ForgePatch\n): void {\n const forge = config.forges?.[key];\n if (!forge) return;\n if (patch.type !== undefined) forge.type = patch.type;\n if (patch.host !== undefined) forge.host = patch.host;\n if (patch.dir !== undefined) forge.dir = patch.dir;\n if (forge.type !== 'git') {\n delete forge.protocol;\n } else if (patch.protocol === null) {\n delete forge.protocol;\n } else if (patch.protocol !== undefined) {\n forge.protocol = patch.protocol;\n }\n}\n","import { readFile, writeFile } from 'node:fs/promises';\nimport { updateConfig } from 'c12/update';\nimport { dirname, extname } from 'pathe';\nimport type { EditableConfig } from './forges.ts';\n\n/**\n * Apply an in-place mutation to a `forgemap.config.*` file, preserving its\n * formatting and comments.\n *\n * `.ts`/`.mts`/`.js`/… are round-tripped through c12's `updateConfig`, which\n * parses the module with magicast and edits the exported object literal — it\n * transparently unwraps a `defineForgeMapConfig(...)` call. Plain `.json`\n * configs, which magicast/updateConfig refuse, are read, mutated and written\n * back directly.\n *\n * Rejects when the source can't be edited safely (e.g. forges built dynamically\n * rather than declared as a literal); callers surface that as a manual-edit\n * fallback rather than crashing.\n */\nexport async function mutateConfigFile(\n path: string,\n mutate: (config: EditableConfig) => void\n): Promise<void> {\n if (extname(path) === '.json') {\n const current = JSON.parse(await readFile(path, 'utf8')) as EditableConfig;\n mutate(current);\n await writeFile(path, `${JSON.stringify(current, null, 2)}\\n`, 'utf8');\n return;\n }\n // `updateConfig` resolves the config by base name from `cwd`; every forgemap\n // config is `forgemap.config.<ext>`, one per directory, so pointing `cwd` at\n // the target file's directory selects exactly that file.\n await updateConfig({\n cwd: dirname(path),\n configFile: 'forgemap.config',\n onUpdate: (config: EditableConfig) => {\n mutate(config);\n }\n });\n}\n","import consola from 'consola';\nimport { colors } from 'consola/utils';\nimport type { ScannedRepo } from './scan.ts';\n\n/**\n * Show the interactive repo picker and return the chosen local path\n * (undefined when the user cancels).\n *\n * `$(forgemap pick)` / `$(forgemap path <q>)` captures stdout, so the\n * interactive TUI must not go there. consola/clack writes the UI to stdout AND\n * reads stdout.rows/columns for layout — but a captured stdout is a pipe (no\n * rows → nothing renders). So for the duration of the prompt: route stdout\n * writes to stderr (the real TTY) and borrow stderr's dimensions, then\n * restore. stdout stays clean for the chosen path only.\n *\n * Callers must check {@link canPrompt} first — without a TTY on stdin there is\n * nobody to answer.\n */\nexport async function promptRepoChoice(\n candidates: ScannedRepo[]\n): Promise<string | undefined> {\n const out = process.stdout;\n const realWrite = out.write;\n const saved = {\n rows: Object.getOwnPropertyDescriptor(out, 'rows'),\n columns: Object.getOwnPropertyDescriptor(out, 'columns'),\n isTTY: Object.getOwnPropertyDescriptor(out, 'isTTY')\n };\n const fake = (key: 'rows' | 'columns' | 'isTTY', value: unknown) => {\n Object.defineProperty(out, key, { configurable: true, value });\n };\n const restore = (key: 'rows' | 'columns' | 'isTTY') => {\n if (saved[key]) Object.defineProperty(out, key, saved[key]!);\n else delete (out as unknown as Record<string, unknown>)[key];\n };\n\n out.write = process.stderr.write.bind(process.stderr) as typeof out.write;\n fake('rows', process.stderr.rows ?? 24);\n fake('columns', process.stderr.columns ?? 80);\n fake('isTTY', true);\n\n let choice: unknown;\n try {\n choice = await consola.prompt('Select a repo', {\n type: 'select',\n options: candidates.map((r) => ({\n label: `${colors.gray(`${r.forgeName}:`)}${r.slug}`,\n value: r.localPath,\n hint: r.localPath\n }))\n });\n } finally {\n out.write = realWrite;\n restore('rows');\n restore('columns');\n restore('isTTY');\n }\n\n return typeof choice === 'string' && choice ? choice : undefined;\n}\n\n/** Whether an interactive prompt can be shown at all. */\nexport function canPrompt(): boolean {\n return Boolean(process.stdin.isTTY);\n}\n","import { existsSync } from 'node:fs';\nimport consola from 'consola';\nimport { join, relative, resolve } from 'pathe';\nimport type { EditableConfig, MutableForge } from '../../config/forges.ts';\nimport type { LoadedConfig } from '../../config/load.ts';\nimport { discoverConfigFiles } from '../../config/load.ts';\nimport { mutateConfigFile } from '../../config/mutate.ts';\nimport { canPrompt } from '../../repos/picker.ts';\n\n/** Whether interactive prompts can be shown (a TTY on stdin to answer them). */\nexport function interactive(): boolean {\n return canPrompt();\n}\n\n/** Prompt for free text. Returns the raw string, or `null` when cancelled. */\nexport async function promptText(\n message: string,\n placeholder?: string\n): Promise<string | null> {\n const answer = await consola.prompt(message, {\n type: 'text',\n placeholder,\n cancel: 'null'\n });\n return typeof answer === 'string' ? answer : null;\n}\n\n/** Prompt to pick one of `options`. Returns the value, or `null` when cancelled. */\nexport async function promptSelect(\n message: string,\n options: readonly string[]\n): Promise<string | null> {\n const answer = await consola.prompt(message, {\n type: 'select',\n options: [...options],\n cancel: 'null'\n });\n return typeof answer === 'string' && answer ? answer : null;\n}\n\n/** Yes/no confirmation. Returns `false` when declined or cancelled. */\nexport async function confirmChange(message: string): Promise<boolean> {\n const answer = await consola.prompt(message, {\n type: 'confirm',\n cancel: 'null'\n });\n return answer === true;\n}\n\nexport interface TargetFile {\n path: string;\n /** The file does not exist yet and will be created (add only). */\n create: boolean;\n}\n\n/**\n * Choose which config file `add` writes to.\n * - `--config <path>` always wins (created when it does not exist).\n * - otherwise discover candidates: one → use it; several with a TTY → present a\n * select (the final step before confirming); several without a TTY → nearest.\n * - nothing discovered → a fresh `forgemap.config.ts` in the cwd.\n *\n * Returns `null` when the user cancels the select.\n */\nexport async function resolveAddTarget(\n explicit: string | undefined\n): Promise<TargetFile | null> {\n if (explicit) {\n const path = resolve(process.cwd(), explicit);\n return { path, create: !existsSync(path) };\n }\n const candidates = discoverConfigFiles();\n if (candidates.length === 0) {\n return { path: join(process.cwd(), 'forgemap.config.ts'), create: true };\n }\n if (candidates.length === 1 || !interactive()) {\n return { path: candidates[0]!.path, create: false };\n }\n const choice = await consola.prompt(\n 'Which config file should this change be written to?',\n {\n type: 'select',\n options: candidates.map((c) => ({\n label: relative(process.cwd(), c.path) || c.path,\n value: c.path,\n hint: c.source\n })),\n cancel: 'null'\n }\n );\n if (typeof choice !== 'string' || !choice) {\n consola.info('Aborted — nothing changed.');\n return null;\n }\n return { path: choice, create: false };\n}\n\n/**\n * The config file `edit`/`remove` operate on — the forge already lives in a real\n * file, so `--config` or the resolved config file is used. Prints an error and\n * returns `null` when only the built-in defaults are in effect (no file).\n */\nexport function existingConfigFile(\n loaded: LoadedConfig,\n explicit: string | undefined\n): string | null {\n if (explicit) return resolve(process.cwd(), explicit);\n if (!loaded.configFile) {\n consola.error(\n 'No forgemap config file found. Run `forgemap config init` or `forgemap forge add` first.'\n );\n return null;\n }\n return loaded.configFile;\n}\n\n/**\n * Round-trip `mutate` into `path`; on failure (a config too dynamic to rewrite)\n * report it and print the change for manual application instead of crashing.\n * Returns whether the file was updated.\n */\nexport async function applyChange(\n path: string,\n mutate: (config: EditableConfig) => void,\n manualHint: () => void\n): Promise<boolean> {\n try {\n await mutateConfigFile(path, mutate);\n return true;\n } catch (error) {\n consola.error(\n `Could not update ${path} automatically: ${(error as Error).message}`\n );\n consola.info('Apply this change by hand instead:');\n manualHint();\n return false;\n }\n}\n\n/** Print a forge as a `forgemap.config` block (the manual-edit fallback). */\nexport function printManualForge(key: string, forge: MutableForge): void {\n consola.log(` ${key}: {`);\n consola.log(` type: '${forge.type}',`);\n consola.log(` host: '${forge.host}',`);\n consola.log(` dir: '${forge.dir}'${forge.protocol ? ',' : ''}`);\n if (forge.protocol) consola.log(` protocol: '${forge.protocol}'`);\n consola.log(' }');\n}\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { dirname } from 'pathe';\nimport {\n DEFAULT_HOSTS,\n FORGE_TYPES,\n GIT_PROTOCOLS,\n addForge,\n buildForge,\n isForgeType,\n isGitProtocol,\n setDefaultForge,\n validateForgeKey\n} from '../../config/forges.ts';\nimport { loadForgeMapConfig } from '../../config/load.ts';\nimport type {\n ForgeMapConfig,\n ForgeType,\n GitProtocol\n} from '../../config/schema.ts';\nimport { writeConfigFile } from '../../config/write.ts';\nimport {\n applyChange,\n confirmChange,\n interactive,\n printManualForge,\n promptSelect,\n promptText,\n resolveAddTarget\n} from './shared.ts';\n\nexport const forgeAddCommand = defineCommand({\n meta: {\n name: 'add',\n description: 'Add a forge to the config (prompts for anything not passed)'\n },\n args: {\n key: {\n type: 'positional',\n required: false,\n description: 'Forge key, e.g. github or work'\n },\n type: {\n type: 'string',\n description: `Forge type (${FORGE_TYPES.join(', ')})`\n },\n host: { type: 'string', description: 'Forge host, e.g. github.com' },\n dir: {\n type: 'string',\n description: 'Directory under root, e.g. comGithub'\n },\n protocol: {\n type: 'string',\n description: `Clone protocol for type=git (${GIT_PROTOCOLS.join(', ')})`\n },\n default: {\n type: 'boolean',\n description: 'Set this forge as the default',\n default: false\n },\n config: {\n type: 'string',\n description: 'Path to the forgemap config file to modify'\n },\n yes: {\n type: 'boolean',\n description: 'Skip the confirmation prompt',\n default: false\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const tty = interactive();\n\n // ---- key ----\n let key = typeof args.key === 'string' ? args.key.trim() : '';\n if (!key && tty) {\n const answer = await promptText('Forge key (e.g. github, work):');\n if (answer === null) return abort();\n key = answer.trim();\n }\n const keyError = validateForgeKey(key);\n if (keyError) return fail(keyError);\n if (loaded.configFile && key in loaded.config.forges) {\n return fail(\n `Forge \"${key}\" already exists. Use \\`forgemap forge edit ${key}\\` to change it.`\n );\n }\n\n // ---- type ----\n let type: ForgeType | undefined;\n if (typeof args.type === 'string') {\n if (!isForgeType(args.type)) return fail(invalidType(args.type));\n type = args.type;\n } else if (tty) {\n const answer = await promptSelect('Forge type:', FORGE_TYPES);\n if (answer === null || !isForgeType(answer)) return abort();\n type = answer;\n }\n if (!type) return fail('Missing forge type. Pass --type.');\n\n // ---- host ----\n const suggestedHost = DEFAULT_HOSTS[type] ?? '';\n let host = typeof args.host === 'string' ? args.host.trim() : '';\n if (!host && tty) {\n const answer = await promptText('Host:', suggestedHost);\n if (answer === null) return abort();\n host = answer.trim() || suggestedHost;\n } else if (!host) {\n host = suggestedHost;\n }\n if (!host) return fail('Missing host. Pass --host.');\n\n // ---- dir ----\n let dir = typeof args.dir === 'string' ? args.dir.trim() : '';\n if (!dir && tty) {\n const answer = await promptText('Directory (under root):');\n if (answer === null) return abort();\n dir = answer.trim();\n }\n if (!dir) return fail('Missing directory. Pass --dir.');\n\n // ---- protocol (git only) ----\n let protocol: GitProtocol | undefined;\n if (type === 'git') {\n if (typeof args.protocol === 'string') {\n if (!isGitProtocol(args.protocol)) {\n return fail(invalidProtocol(args.protocol));\n }\n protocol = args.protocol;\n } else if (tty) {\n const answer = await promptSelect('Clone protocol:', GIT_PROTOCOLS);\n if (answer !== null && isGitProtocol(answer)) protocol = answer;\n }\n }\n\n // ---- default forge? ----\n // A brand-new config needs a default, so the first forge always becomes it.\n let makeDefault = args.default === true;\n if (!loaded.configFile) {\n makeDefault = true;\n } else if (!makeDefault && tty) {\n makeDefault = await confirmChange(`Set \"${key}\" as the default forge?`);\n }\n\n const forge = buildForge({ type, host, dir, protocol });\n\n // ---- target file (the final choice before applying) ----\n const target = await resolveAddTarget(args.config);\n if (!target) return;\n\n consola.info(\n `Add forge \"${key}\" (${type} → ${host}) into ${target.create ? 'new ' : ''}${target.path}`\n );\n if (tty && !args.yes && !(await confirmChange('Apply this change?'))) {\n return abort();\n }\n\n // ---- apply ----\n if (target.create) {\n const config: ForgeMapConfig = {\n root: loaded.config.root,\n defaultForge: key,\n forges: { [key]: forge }\n };\n const written = await writeConfigFile(config, {\n outDir: dirname(target.path)\n });\n if (!written) return fail(`${target.path} already exists.`);\n consola.success(`Added forge \"${key}\" — wrote ${written.path}`);\n return;\n }\n\n const applied = await applyChange(\n target.path,\n (c) => {\n addForge(c, key, forge);\n if (makeDefault) setDefaultForge(c, key);\n },\n () => printManualForge(key, forge)\n );\n if (applied) consola.success(`Added forge \"${key}\" to ${target.path}`);\n else process.exitCode = 1;\n }\n});\n\nfunction fail(message: string): void {\n consola.error(message);\n process.exitCode = 1;\n}\n\nfunction abort(): void {\n consola.info('Aborted — nothing changed.');\n}\n\nfunction invalidType(value: string): string {\n return `Invalid type \"${value}\". Expected one of: ${FORGE_TYPES.join(', ')}.`;\n}\n\nfunction invalidProtocol(value: string): string {\n return `Invalid protocol \"${value}\". Expected one of: ${GIT_PROTOCOLS.join(', ')}.`;\n}\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport {\n FORGE_TYPES,\n GIT_PROTOCOLS,\n type ForgePatch,\n type MutableForge,\n editForge,\n isForgeType,\n isGitProtocol\n} from '../../config/forges.ts';\nimport { loadForgeMapConfig } from '../../config/load.ts';\nimport type { ForgeType, GitProtocol } from '../../config/schema.ts';\nimport {\n applyChange,\n confirmChange,\n existingConfigFile,\n interactive,\n printManualForge,\n promptSelect,\n promptText\n} from './shared.ts';\n\nexport const forgeEditCommand = defineCommand({\n meta: {\n name: 'edit',\n description:\n 'Edit an existing forge (prompts for fields when none are passed)'\n },\n args: {\n key: {\n type: 'positional',\n required: false,\n description: 'Forge key to edit'\n },\n type: {\n type: 'string',\n description: `New forge type (${FORGE_TYPES.join(', ')})`\n },\n host: { type: 'string', description: 'New host' },\n dir: { type: 'string', description: 'New directory under root' },\n protocol: {\n type: 'string',\n description: `New clone protocol for type=git (${GIT_PROTOCOLS.join(', ')})`\n },\n config: {\n type: 'string',\n description: 'Path to the forgemap config file to modify'\n },\n yes: {\n type: 'boolean',\n description: 'Skip the confirmation prompt',\n default: false\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const tty = interactive();\n\n const file = existingConfigFile(loaded, args.config);\n if (!file) {\n process.exitCode = 1;\n return;\n }\n\n const forges = loaded.config.forges;\n\n // ---- which forge ----\n let key = typeof args.key === 'string' ? args.key.trim() : '';\n if (!key && tty) {\n const answer = await promptSelect(\n 'Which forge should be edited?',\n Object.keys(forges)\n );\n if (answer === null) return abort();\n key = answer;\n }\n if (!key) return fail('Missing forge key. Pass it as an argument.');\n const current = forges[key];\n if (!current) {\n return fail(\n `No forge \"${key}\" in ${file}. Configured: ${Object.keys(forges).join(', ')}.`\n );\n }\n const currentProtocol =\n current.type === 'git' ? current.protocol : undefined;\n\n const patch: ForgePatch = {};\n\n // ---- type ----\n if (typeof args.type === 'string') {\n if (!isForgeType(args.type)) return fail(invalidType(args.type));\n patch.type = args.type;\n } else if (tty) {\n const answer = await promptSelect(\n `Type (current: ${current.type}):`,\n FORGE_TYPES\n );\n if (answer === null) return abort();\n if (isForgeType(answer)) patch.type = answer;\n }\n const resultType: ForgeType = patch.type ?? current.type;\n\n // ---- host ----\n if (typeof args.host === 'string') {\n patch.host = args.host.trim();\n } else if (tty) {\n const answer = await promptText(\n `Host (current: ${current.host}):`,\n current.host\n );\n if (answer === null) return abort();\n if (answer.trim()) patch.host = answer.trim();\n }\n\n // ---- dir ----\n if (typeof args.dir === 'string') {\n patch.dir = args.dir.trim();\n } else if (tty) {\n const answer = await promptText(\n `Directory (current: ${current.dir}):`,\n current.dir\n );\n if (answer === null) return abort();\n if (answer.trim()) patch.dir = answer.trim();\n }\n\n // ---- protocol (only when the resulting type is git) ----\n if (resultType === 'git') {\n if (typeof args.protocol === 'string') {\n if (!isGitProtocol(args.protocol)) {\n return fail(invalidProtocol(args.protocol));\n }\n patch.protocol = args.protocol;\n } else if (tty) {\n const answer = await promptSelect('Clone protocol:', GIT_PROTOCOLS);\n if (answer !== null && isGitProtocol(answer)) patch.protocol = answer;\n }\n }\n\n if (!hasChanges(patch)) {\n return fail(\n 'Nothing to change. Pass --type, --host, --dir or --protocol.'\n );\n }\n\n consola.info(`Edit forge \"${key}\" in ${file}`);\n if (tty && !args.yes && !(await confirmChange('Apply this change?'))) {\n return abort();\n }\n\n const merged = mergeForge(current, currentProtocol, patch, resultType);\n const applied = await applyChange(\n file,\n (c) => editForge(c, key, patch),\n () => {\n consola.log(`Update the \"${key}\" entry to:`);\n printManualForge(key, merged);\n }\n );\n if (applied) consola.success(`Edited forge \"${key}\" in ${file}`);\n else process.exitCode = 1;\n }\n});\n\nfunction hasChanges(patch: ForgePatch): boolean {\n return (\n patch.type !== undefined ||\n patch.host !== undefined ||\n patch.dir !== undefined ||\n patch.protocol !== undefined\n );\n}\n\nfunction mergeForge(\n current: { type: ForgeType; host: string; dir: string },\n currentProtocol: GitProtocol | undefined,\n patch: ForgePatch,\n resultType: ForgeType\n): MutableForge {\n // `ForgePatch.protocol` can be null (editForge reads that as \"clear it\"), but\n // this command never sets it — a protocol only ever goes away by leaving git.\n const protocol =\n resultType === 'git' ? (patch.protocol ?? currentProtocol) : undefined;\n return {\n type: resultType,\n host: patch.host ?? current.host,\n dir: patch.dir ?? current.dir,\n ...(protocol ? { protocol } : {})\n };\n}\n\nfunction fail(message: string): void {\n consola.error(message);\n process.exitCode = 1;\n}\n\nfunction abort(): void {\n consola.info('Aborted — nothing changed.');\n}\n\nfunction invalidType(value: string): string {\n return `Invalid type \"${value}\". Expected one of: ${FORGE_TYPES.join(', ')}.`;\n}\n\nfunction invalidProtocol(value: string): string {\n return `Invalid protocol \"${value}\". Expected one of: ${GIT_PROTOCOLS.join(', ')}.`;\n}\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { removeForge, setDefaultForge } from '../../config/forges.ts';\nimport { loadForgeMapConfig } from '../../config/load.ts';\nimport {\n applyChange,\n confirmChange,\n existingConfigFile,\n interactive,\n promptSelect\n} from './shared.ts';\n\nconst LEAVE_UNSET = '— leave unset —';\n\nexport const forgeRemoveCommand = defineCommand({\n meta: {\n name: 'remove',\n description: 'Remove a forge from the config'\n },\n args: {\n key: {\n type: 'positional',\n required: false,\n description: 'Forge key to remove'\n },\n default: {\n type: 'string',\n description:\n 'When removing the default forge, reassign the default to this'\n },\n config: {\n type: 'string',\n description: 'Path to the forgemap config file to modify'\n },\n yes: {\n type: 'boolean',\n description: 'Skip the confirmation prompt',\n default: false\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const tty = interactive();\n\n const file = existingConfigFile(loaded, args.config);\n if (!file) {\n process.exitCode = 1;\n return;\n }\n\n const forges = loaded.config.forges;\n\n // ---- which forge ----\n let key = typeof args.key === 'string' ? args.key.trim() : '';\n if (!key && tty) {\n const answer = await promptSelect(\n 'Which forge should be removed?',\n Object.keys(forges)\n );\n if (answer === null) return abort();\n key = answer;\n }\n if (!key) return fail('Missing forge key. Pass it as an argument.');\n if (!(key in forges)) {\n return fail(\n `No forge \"${key}\" in ${file}. Configured: ${Object.keys(forges).join(', ')}.`\n );\n }\n\n // ---- reassign the default when it is the one being removed ----\n const remaining = Object.keys(forges).filter((k) => k !== key);\n let newDefault: string | undefined;\n if (loaded.config.defaultForge === key && remaining.length > 0) {\n if (typeof args.default === 'string') {\n if (!remaining.includes(args.default)) {\n return fail(\n `Cannot set default to \"${args.default}\" — not a remaining forge (${remaining.join(', ')}).`\n );\n }\n newDefault = args.default;\n } else if (tty) {\n const answer = await promptSelect(\n `\"${key}\" is the default forge. Pick a new default:`,\n [...remaining, LEAVE_UNSET]\n );\n if (answer === null) return abort();\n if (answer !== LEAVE_UNSET) newDefault = answer;\n } else {\n consola.warn(\n `Removing the default forge \"${key}\"; defaultForge now points at a missing forge. Pass --default to reassign it.`\n );\n }\n }\n\n consola.info(\n `Remove forge \"${key}\" from ${file}${newDefault ? ` (new default: \"${newDefault}\")` : ''}`\n );\n if (tty && !args.yes && !(await confirmChange('Apply this change?'))) {\n return abort();\n }\n\n const applied = await applyChange(\n file,\n (c) => {\n removeForge(c, key);\n if (newDefault) setDefaultForge(c, newDefault);\n },\n () => consola.log(`Remove the \"${key}\" entry from \\`forges\\` in ${file}.`)\n );\n if (applied) consola.success(`Removed forge \"${key}\" from ${file}`);\n else process.exitCode = 1;\n }\n});\n\nfunction fail(message: string): void {\n consola.error(message);\n process.exitCode = 1;\n}\n\nfunction abort(): void {\n consola.info('Aborted — nothing changed.');\n}\n","import { defineCommand } from 'citty';\nimport { forgeAddCommand } from './add.ts';\nimport { forgeEditCommand } from './edit.ts';\nimport { forgeRemoveCommand } from './remove.ts';\n\nexport const forgeCommand = defineCommand({\n meta: {\n name: 'forge',\n description: 'Add, remove or edit forges in the config'\n },\n subCommands: {\n add: forgeAddCommand,\n remove: forgeRemoveCommand,\n edit: forgeEditCommand\n }\n});\n","import { readdir } from 'node:fs/promises';\nimport { join } from 'pathe';\nimport type {\n ForgeConfig,\n ForgeMapConfig,\n ForgeType\n} from '../config/schema.ts';\nimport { getForgeAdapter } from '../forges/registry.ts';\nimport type { RemoteCheckInput, RemoteCheckResult } from '../forges/types.ts';\nimport { mapLimit } from '../utils/concurrency.ts';\nimport { parseSlug } from '../slug/parse.ts';\nimport { getOriginUrl, getRemotes, isGitRepo, type GitRemote } from './git.ts';\n\n/** Layout kinds importable today. `forgemap` = the `<server>/<owner>/<repo>`\n * tree forgemap itself manages. Kept as an enum to extend later. */\nexport type ImportType = 'forgemap';\n\nexport interface ImportOptions {\n /** Absolute path to scan (already expanded/resolved). */\n path: string;\n type: ImportType;\n /** Run the per-forge network existence/move check. Default true. */\n remoteCheck: boolean;\n /** Called as remote checks complete, for progress reporting. */\n onProgress?: (done: number, total: number) => void;\n}\n\nexport interface DiscoveredRepo {\n serverDir: string;\n owner: string;\n repo: string;\n localPath: string;\n}\n\nexport type FindingKind =\n | 'not-a-git-repo'\n | 'no-origin'\n | 'multiple-remotes'\n | 'origin-mismatch'\n | 'remote-moved'\n | 'remote-gone'\n | 'host-unmatched'\n | 'remote-check-skipped'\n | 'remote-check-unknown';\n\nexport type FindingSeverity = 'ok' | 'warn' | 'fail';\n\nexport type Fix =\n | { action: 'move-folder'; from: string; to: string }\n | { action: 'set-origin-url'; localPath: string; url: string };\n\nexport interface Finding {\n kind: FindingKind;\n severity: FindingSeverity;\n message: string;\n fix?: Fix;\n}\n\nexport interface RepoReport {\n repo: DiscoveredRepo;\n originUrl: string | null;\n /** Host parsed from the origin URL, when parseable. Drives config derivation. */\n originHost: string | null;\n remotes: GitRemote[];\n findings: Finding[];\n}\n\nexport interface DerivedConfig extends ForgeMapConfig {}\n\nexport interface ImportResult {\n root: string;\n derived: DerivedConfig;\n reports: RepoReport[];\n}\n\nasync function listDirs(path: string): Promise<string[]> {\n try {\n const entries = await readdir(path, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => e.name);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw error;\n }\n}\n\n/**\n * Structure-driven depth-3 walk of `<path>/<serverDir>/<owner>/<repo>`.\n * Unlike `scanRepos`, this is config-free: every top-level directory is a\n * candidate server dir, and the names are discovered rather than configured.\n */\nexport async function discoverForgemapLayout(\n path: string\n): Promise<DiscoveredRepo[]> {\n const repos: DiscoveredRepo[] = [];\n for (const serverDir of await listDirs(path)) {\n const serverPath = join(path, serverDir);\n for (const owner of await listDirs(serverPath)) {\n const ownerPath = join(serverPath, owner);\n for (const repo of await listDirs(ownerPath)) {\n repos.push({\n serverDir,\n owner,\n repo,\n localPath: join(ownerPath, repo)\n });\n }\n }\n }\n return repos;\n}\n\nfunction forgeTypeForHost(host: string): ForgeType {\n return host === 'github.com' ? 'github' : 'git';\n}\n\n/**\n * Derive a `root` + one forge per server dir from the analyzed reports.\n * Host (and therefore type) come from the dominant origin host of the repos\n * under each server dir.\n */\nexport function deriveConfig(\n reports: RepoReport[],\n path: string\n): DerivedConfig {\n const forges: Record<string, ForgeConfig> = {};\n const counts = new Map<string, number>();\n\n const byServer = new Map<string, RepoReport[]>();\n for (const report of reports) {\n const list = byServer.get(report.repo.serverDir);\n if (list) list.push(report);\n else byServer.set(report.repo.serverDir, [report]);\n }\n\n for (const [serverDir, group] of byServer) {\n counts.set(serverDir, group.length);\n const hostTally = new Map<string, number>();\n for (const report of group) {\n if (report.originHost) {\n hostTally.set(\n report.originHost,\n (hostTally.get(report.originHost) ?? 0) + 1\n );\n }\n }\n const host =\n [...hostTally.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? '';\n const type = host ? forgeTypeForHost(host) : 'git';\n forges[serverDir] = { type, host, dir: serverDir } as ForgeConfig;\n }\n\n // Prefer a github forge, then the one with the most repos.\n const names = Object.keys(forges);\n const defaultForge =\n names.slice().sort((a, b) => {\n const aGh = forges[a]!.type === 'github' ? 1 : 0;\n const bGh = forges[b]!.type === 'github' ? 1 : 0;\n if (aGh !== bGh) return bGh - aGh;\n return (counts.get(b) ?? 0) - (counts.get(a) ?? 0);\n })[0] ?? '';\n\n return { root: path, defaultForge, forges };\n}\n\n/** Parsed origin identity carried between the local and remote phases. */\ninterface ParsedOrigin {\n host?: string;\n owner: string;\n repo: string;\n}\n\n/** Local phase: git reads + offline folder-vs-origin reconciliation. No network. */\nasync function analyzeLocal(\n repo: DiscoveredRepo,\n options: ImportOptions\n): Promise<{ report: RepoReport; parsed: ParsedOrigin | null }> {\n const report: RepoReport = {\n repo,\n originUrl: null,\n originHost: null,\n remotes: [],\n findings: []\n };\n\n if (!(await isGitRepo(repo.localPath))) {\n report.findings.push({\n kind: 'not-a-git-repo',\n severity: 'warn',\n message: 'not a git repository'\n });\n return { report, parsed: null };\n }\n\n report.remotes = await getRemotes(repo.localPath);\n report.originUrl = await getOriginUrl(repo.localPath);\n\n if (!report.originUrl) {\n const names = report.remotes\n .map((r) => r.name)\n .filter((n) => n !== 'origin');\n report.findings.push({\n kind: 'no-origin',\n severity: 'warn',\n message:\n names.length > 0\n ? `no origin remote (other remotes: ${names.join(', ')})`\n : 'no origin remote'\n });\n return { report, parsed: null };\n }\n\n if (report.remotes.length > 1) {\n report.findings.push({\n kind: 'multiple-remotes',\n severity: 'warn',\n message: `${report.remotes.length} remotes configured; comparing origin`\n });\n }\n\n let parsed: ParsedOrigin | null = null;\n try {\n parsed = parseSlug(report.originUrl);\n report.originHost = parsed.host ?? null;\n } catch {\n report.findings.push({\n kind: 'origin-mismatch',\n severity: 'warn',\n message: `could not parse origin URL: ${report.originUrl}`\n });\n }\n\n if (parsed && (parsed.owner !== repo.owner || parsed.repo !== repo.repo)) {\n const to = join(options.path, repo.serverDir, parsed.owner, parsed.repo);\n report.findings.push({\n kind: 'origin-mismatch',\n severity: 'warn',\n message: `folder ${repo.owner}/${repo.repo} != origin ${parsed.owner}/${parsed.repo}`,\n fix: { action: 'move-folder', from: repo.localPath, to }\n });\n }\n\n return { report, parsed };\n}\n\n/** Translate a remote-check result into a finding on the report. */\nfunction pushRemoteFinding(\n report: RepoReport,\n parsed: ParsedOrigin,\n result: RemoteCheckResult,\n path: string\n): void {\n const { repo } = report;\n switch (result.state) {\n case 'exists':\n break;\n case 'moved': {\n const to = join(\n path,\n repo.serverDir,\n result.canonical.owner,\n result.canonical.repo\n );\n const fix: Fix | undefined = result.canonicalUrl\n ? {\n action: 'set-origin-url',\n localPath: repo.localPath,\n url: result.canonicalUrl\n }\n : to !== repo.localPath\n ? { action: 'move-folder', from: repo.localPath, to }\n : undefined;\n report.findings.push({\n kind: 'remote-moved',\n severity: 'warn',\n message: `remote moved to ${result.canonical.owner}/${result.canonical.repo}`,\n fix\n });\n break;\n }\n case 'gone':\n report.findings.push({\n kind: 'remote-gone',\n severity: 'warn',\n message: `remote ${parsed.owner}/${parsed.repo} no longer exists`\n });\n break;\n case 'unknown':\n report.findings.push({\n kind: 'remote-check-unknown',\n severity: 'warn',\n message: `remote check inconclusive: ${result.reason}`\n });\n break;\n }\n}\n\n/** A repo that has a parseable origin and is therefore eligible for the\n * network check, paired with its derived forge. */\ninterface Checkable {\n report: RepoReport;\n parsed: ParsedOrigin;\n}\n\n/** Run the network check for one forge's repos, preferring the batched\n * adapter method and falling back to a concurrency-limited per-repo loop. */\nasync function checkForgeGroup(\n forge: ForgeConfig,\n items: Checkable[],\n options: ImportOptions,\n bump: () => void\n): Promise<void> {\n const inputs: RemoteCheckInput[] = items.map((it) => ({\n forge,\n owner: it.parsed.owner,\n repo: it.parsed.repo,\n originUrl: it.report.originUrl ?? undefined\n }));\n\n let adapter: ReturnType<typeof getForgeAdapter>;\n try {\n adapter = getForgeAdapter(forge.type);\n } catch (error) {\n for (const it of items) {\n it.report.findings.push({\n kind: 'remote-check-unknown',\n severity: 'warn',\n message: `remote check inconclusive: ${(error as Error).message}`\n });\n bump();\n }\n return;\n }\n\n if (adapter.checkRemotes) {\n let results: RemoteCheckResult[];\n try {\n results = await adapter.checkRemotes(inputs);\n } catch (error) {\n results = inputs.map(() => ({\n state: 'unknown',\n reason: (error as Error).message\n }));\n }\n items.forEach((it, i) => {\n pushRemoteFinding(it.report, it.parsed, results[i]!, options.path);\n bump();\n });\n return;\n }\n\n const check = adapter.checkRemote;\n await mapLimit(items, REMOTE_CONCURRENCY, async (it, i) => {\n let result: RemoteCheckResult;\n try {\n result = check\n ? await check(inputs[i]!)\n : { state: 'unknown', reason: `${forge.type} has no remote check` };\n } catch (error) {\n result = { state: 'unknown', reason: (error as Error).message };\n }\n pushRemoteFinding(it.report, it.parsed, result, options.path);\n bump();\n });\n}\n\nconst LOCAL_CONCURRENCY = 16;\nconst REMOTE_CONCURRENCY = 10;\n\n/** Discover, reconcile, and (optionally) network-check an importable tree. */\nexport async function analyzeImport(\n options: ImportOptions\n): Promise<ImportResult> {\n const discovered = await discoverForgemapLayout(options.path);\n\n const locals = await mapLimit(discovered, LOCAL_CONCURRENCY, (repo) =>\n analyzeLocal(repo, options)\n );\n const reports = locals.map((l) => l.report);\n const derived = deriveConfig(reports, options.path);\n\n // host-unmatched is offline but needs the derived forge to compare against.\n for (const { report, parsed } of locals) {\n const forge = derived.forges[report.repo.serverDir];\n if (parsed?.host && forge?.host && parsed.host !== forge.host) {\n report.findings.push({\n kind: 'host-unmatched',\n severity: 'warn',\n message: `origin host ${parsed.host} differs from forge host ${forge.host}`\n });\n }\n }\n\n const checkable: Checkable[] = locals.flatMap((l) =>\n l.report.originUrl && l.parsed\n ? [{ report: l.report, parsed: l.parsed }]\n : []\n );\n\n if (!options.remoteCheck) {\n for (const { report } of checkable) {\n report.findings.push({\n kind: 'remote-check-skipped',\n severity: 'ok',\n message: 'remote check skipped (--no-remote-check)'\n });\n }\n return { root: options.path, derived, reports };\n }\n\n const total = checkable.length;\n let done = 0;\n const bump = () => {\n done++;\n options.onProgress?.(done, total);\n };\n options.onProgress?.(0, total);\n\n // Group by server dir so each forge's repos can be checked in one batch.\n const groups = new Map<string, Checkable[]>();\n for (const item of checkable) {\n const key = item.report.repo.serverDir;\n const list = groups.get(key);\n if (list) list.push(item);\n else groups.set(key, [item]);\n }\n\n await Promise.all(\n Array.from(groups, ([serverDir, items]) => {\n const forge = derived.forges[serverDir];\n if (!forge) {\n for (const it of items) {\n it.report.findings.push({\n kind: 'remote-check-unknown',\n severity: 'warn',\n message: 'no forge derived for this server dir'\n });\n bump();\n }\n return Promise.resolve();\n }\n return checkForgeGroup(forge, items, options, bump);\n })\n );\n\n return { root: options.path, derived, reports };\n}\n","import { existsSync } from 'node:fs';\nimport { mkdir, rename, stat } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors, formatTree } from 'consola/utils';\nimport { dirname, join, resolve } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport type { ForgeConfig, ForgeMapConfig } from '../config/schema.ts';\nimport { writeConfigFile } from '../config/write.ts';\nimport { scanReposCached } from '../repos/cache.ts';\nimport { setOriginUrl } from '../repos/git.ts';\nimport {\n analyzeImport,\n type Finding,\n type FindingSeverity,\n type Fix,\n type ImportType,\n type RepoReport\n} from '../repos/import.ts';\n\nconst ALLOWED_TYPES: ImportType[] = ['forgemap'];\nconst ALLOWED_FORMATS = ['pretty', 'json'];\n\nfunction isImportType(value: string): value is ImportType {\n return (ALLOWED_TYPES as string[]).includes(value);\n}\n\nfunction severitySymbol(severity: FindingSeverity): string {\n if (severity === 'fail') return colors.red('✗');\n if (severity === 'warn') return colors.yellow('!');\n return colors.green('✓');\n}\n\nfunction worstSeverity(findings: Finding[]): FindingSeverity {\n if (findings.some((f) => f.severity === 'fail')) return 'fail';\n if (findings.some((f) => f.severity === 'warn')) return 'warn';\n return 'ok';\n}\n\nfunction hasIssues(report: RepoReport): boolean {\n return report.findings.some((f) => f.severity !== 'ok');\n}\n\nfunction repoLine(report: RepoReport): string {\n const symbol = severitySymbol(worstSeverity(report.findings));\n const name = colors.cyan(report.repo.repo);\n const issues = report.findings.filter((f) => f.severity !== 'ok');\n if (issues.length === 0) return `${symbol} ${name}`;\n const summary = issues.map((f) => f.message).join('; ');\n return `${symbol} ${name} ${colors.dim(summary)}`;\n}\n\n// Three levels, like a path: serverDir → owner → repo.\nfunction renderReports(reports: RepoReport[]): string {\n const byServer = new Map<string, Map<string, RepoReport[]>>();\n for (const report of reports) {\n let owners = byServer.get(report.repo.serverDir);\n if (!owners) {\n owners = new Map();\n byServer.set(report.repo.serverDir, owners);\n }\n const list = owners.get(report.repo.owner);\n if (list) list.push(report);\n else owners.set(report.repo.owner, [report]);\n }\n return formatTree(\n Array.from(byServer, ([serverDir, owners]) => ({\n text: colors.bold(serverDir),\n children: Array.from(owners, ([owner, items]) => ({\n text: owner,\n children: items.map((report) => ({ text: repoLine(report) }))\n }))\n }))\n );\n}\n\nfunction renderDerived(config: ForgeMapConfig): string {\n return formatTree([\n {\n text: colors.bold('Derived config'),\n children: Object.entries(config.forges).map(([name, forge]) => ({\n text: `${colors.cyan(name)} ${colors.dim(\n `${forge.type} @ ${forge.host || '(unknown host)'} → ${forge.dir}`\n )}`\n }))\n }\n ]);\n}\n\nasync function applyFixes(reports: RepoReport[]): Promise<Fix[]> {\n const applied: Fix[] = [];\n const fixes = reports.flatMap((r) =>\n r.findings.flatMap((f) => (f.fix ? [f.fix] : []))\n );\n\n // Repoint URLs first so a repo's git config is corrected before it moves.\n for (const fix of fixes) {\n if (fix.action !== 'set-origin-url') continue;\n const result = await setOriginUrl(fix.localPath, fix.url);\n if (result.code === 0) {\n applied.push(fix);\n consola.success(`origin → ${fix.url}`);\n } else {\n consola.warn(\n `failed to set origin for ${fix.localPath}: ${result.stderr.trim()}`\n );\n }\n }\n\n for (const fix of fixes) {\n if (fix.action !== 'move-folder') continue;\n if (existsSync(fix.to)) {\n consola.warn(`skip move: target exists ${fix.to}`);\n continue;\n }\n await mkdir(dirname(fix.to), { recursive: true });\n await rename(fix.from, fix.to);\n applied.push(fix);\n consola.success(`moved ${fix.from} → ${fix.to}`);\n }\n\n return applied;\n}\n\n/** Merge derived forges into an existing config without clobbering existing\n * keys. Returns the merged config plus any conflicting keys. */\nfunction augmentConfig(\n existing: ForgeMapConfig,\n derived: ForgeMapConfig\n): { merged: ForgeMapConfig; conflicts: string[] } {\n const forges: Record<string, ForgeConfig> = { ...existing.forges };\n const conflicts: string[] = [];\n for (const [name, forge] of Object.entries(derived.forges)) {\n const current = existing.forges[name];\n if (!current) {\n forges[name] = forge;\n } else if (current.host !== forge.host) {\n conflicts.push(name);\n }\n }\n return { merged: { ...existing, forges }, conflicts };\n}\n\nexport const importCommand = defineCommand({\n meta: {\n name: 'import',\n description:\n 'Adopt an existing repo tree: reconcile folders against git remotes and derive a config'\n },\n args: {\n path: {\n type: 'positional',\n description: 'Directory laid out as <server>/<owner>/<repo>',\n required: true\n },\n type: {\n type: 'string',\n description: 'Layout type (currently only \"forgemap\")',\n default: 'forgemap'\n },\n format: {\n type: 'string',\n description: 'Output format: pretty (default) or json',\n default: 'pretty'\n },\n 'remote-check': {\n type: 'boolean',\n description: 'Check each remote for existence/moves (default true)',\n default: true\n },\n fix: {\n type: 'boolean',\n description: 'Apply corrections (move folders, repoint origin URLs)',\n default: false\n },\n 'write-config': {\n type: 'boolean',\n description:\n 'Write/augment forgemap.config.ts from the derived structure',\n default: true\n },\n out: {\n type: 'string',\n description:\n 'Directory to write the derived config into (defaults to <path>)'\n },\n force: {\n type: 'boolean',\n description: 'Overwrite an existing config instead of augmenting it',\n default: false\n }\n },\n async run({ args }) {\n if (!isImportType(args.type)) {\n consola.error(\n `Invalid --type value \"${args.type}\". Allowed: ${ALLOWED_TYPES.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n if (!ALLOWED_FORMATS.includes(args.format)) {\n consola.error(\n `Invalid --format value \"${args.format}\". Allowed: ${ALLOWED_FORMATS.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n\n const path = resolve(process.cwd(), args.path);\n try {\n const s = await stat(path);\n if (!s.isDirectory()) {\n consola.error(`${path} is not a directory.`);\n process.exitCode = 1;\n return;\n }\n } catch {\n consola.error(`${path} does not exist.`);\n process.exitCode = 1;\n return;\n }\n\n // Progress for the (potentially slow) remote checks. stderr-only and\n // TTY-guarded so it never corrupts JSON on stdout or piped logs.\n const showProgress = args['remote-check'] && Boolean(process.stderr.isTTY);\n let clearLen = 0;\n const onProgress = showProgress\n ? (done: number, total: number) => {\n const msg = `⏳ Checking remotes ${done}/${total}`;\n process.stderr.write(`\\r${msg} `);\n clearLen = msg.length + 1;\n }\n : undefined;\n\n const result = await analyzeImport({\n path,\n type: args.type,\n remoteCheck: args['remote-check'],\n onProgress\n });\n\n if (clearLen > 0) {\n process.stderr.write(`\\r${' '.repeat(clearLen)}\\r`);\n }\n\n const applied = args.fix ? await applyFixes(result.reports) : [];\n\n const withFindings = result.reports.filter(hasIssues).length;\n const fixable = result.reports.reduce(\n (n, r) => n + r.findings.filter((f) => f.fix).length,\n 0\n );\n\n if (args.format === 'json') {\n process.stdout.write(\n `${JSON.stringify(\n {\n path,\n type: args.type,\n derived: result.derived,\n repos: result.reports.map((r) => ({\n serverDir: r.repo.serverDir,\n owner: r.repo.owner,\n repo: r.repo.repo,\n localPath: r.repo.localPath,\n originUrl: r.originUrl,\n remotes: r.remotes,\n findings: r.findings\n })),\n ...(args.fix ? { applied } : {}),\n summary: { repos: result.reports.length, withFindings, fixable }\n },\n null,\n 2\n )}\\n`\n );\n } else {\n process.stdout.write(\n `${colors.dim(`Scanned ${path} (${args.type})`)}\\n\\n`\n );\n if (result.reports.length === 0) {\n consola.info('No repos found.');\n } else {\n process.stdout.write(`${renderReports(result.reports)}\\n\\n`);\n }\n process.stdout.write(`${renderDerived(result.derived)}\\n\\n`);\n process.stdout.write(\n `${colors.bold(`${result.reports.length} repos`)}, ${withFindings} with findings, ${fixable} fixable${\n args.fix ? `, ${applied.length} fixed` : ''\n }\\n`\n );\n }\n\n if (!args['write-config']) return;\n if (result.reports.length === 0 && !args.force) return;\n\n const outDir = args.out ? resolve(process.cwd(), args.out) : path;\n const writableRoot = outDir === path ? '.' : path;\n const target = join(outDir, 'forgemap.config.ts');\n\n if (existsSync(target) && !args.force) {\n const loaded = await loadForgeMapConfig({ configFile: target });\n const { merged, conflicts } = augmentConfig(\n loaded.config,\n result.derived\n );\n for (const name of conflicts) {\n consola.warn(\n `forge \"${name}\" already exists with a different host — left untouched`\n );\n }\n await writeConfigFile(merged, { outDir, force: true });\n consola.success(`Augmented ${target}`);\n } else {\n const written = await writeConfigFile(\n { ...result.derived, root: writableRoot },\n { outDir, force: args.force }\n );\n if (written) consola.success(`Wrote ${written.path}`);\n }\n\n // Warm the scan cache so the next status/list hits the hot path.\n await scanReposCached({\n config: result.derived,\n configDir: path,\n useCache: false\n });\n }\n});\n","import { existsSync, readFileSync, realpathSync } from 'node:fs';\nimport { defineCommand } from 'citty';\nimport { colors } from 'consola/utils';\nimport { dirname, join, resolve } from 'pathe';\nimport { type ConfigSource, loadForgeMapConfig } from '../config/load.ts';\nimport { resolveRoot } from '../utils/path.ts';\n\n// Injected at build time by vite's `define` (see vite.config.ts), sourced from\n// package.json's `version`. Read it the same way `cli.ts` does rather than\n// re-inventing a drift-prone literal.\ndeclare const __APP_VERSION__: string;\n\n/** `linked` = runs from a git work tree; `release` = an installed package. */\ntype BuildKind = 'linked' | 'release' | 'unknown';\n\ninterface BuildInfo {\n kind: BuildKind;\n /** Directory of the nearest `forgemap` package.json above the binary. */\n packageRoot: string | null;\n reason: string;\n}\n\ninterface BinaryInfo {\n /** The path as invoked (may be a shim / symlink). */\n invoked: string | null;\n /** The real executed file, symlinks resolved. */\n resolved: string | null;\n}\n\ninterface ForgeInfo {\n name: string;\n type: string;\n dir: string;\n}\n\ninterface ConfigInfo {\n source: ConfigSource | 'error';\n file: string | null;\n root: string | null;\n forges: ForgeInfo[];\n /** Set when the config could not be loaded (missing/broken); else null. */\n error: string | null;\n}\n\ninterface Info {\n version: string;\n build: BuildInfo;\n binary: BinaryInfo;\n node: string;\n config: ConfigInfo;\n}\n\n/** Resolve the real executed file behind any shim or symlink. */\nfunction resolveBinary(entry: string | undefined): BinaryInfo {\n if (!entry) return { invoked: null, resolved: null };\n try {\n return { invoked: entry, resolved: realpathSync(entry) };\n } catch {\n // The file vanished (or is unreadable) — report the invoked path as-is\n // rather than failing; `info` describes, it never judges.\n return { invoked: entry, resolved: entry };\n }\n}\n\n/** Walk up from `start` to the nearest package.json, returning its dir + name. */\nfunction findPackageRoot(\n start: string\n): { dir: string; name: string | undefined } | null {\n let dir = resolve(start);\n for (;;) {\n const pkgPath = join(dir, 'package.json');\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as {\n name?: string;\n };\n return { dir, name: pkg.name };\n } catch {\n return { dir, name: undefined };\n }\n }\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\n/**\n * Distinguish a linked/dev build from an installed release: the resolved binary\n * lives inside a git work tree whose package.json is named `forgemap`. An\n * installed package has the same package.json but no `.git` beside it. When the\n * binary or a `forgemap` package.json cannot be located, report `unknown`\n * rather than guessing.\n */\nfunction detectBuild(resolved: string | null): BuildInfo {\n if (!resolved) {\n return {\n kind: 'unknown',\n packageRoot: null,\n reason: 'binary path could not be resolved'\n };\n }\n const pkg = findPackageRoot(dirname(resolved));\n if (!pkg) {\n return {\n kind: 'unknown',\n packageRoot: null,\n reason: 'no package.json found above the binary'\n };\n }\n if (pkg.name !== 'forgemap') {\n return {\n kind: 'unknown',\n packageRoot: pkg.dir,\n reason: `nearest package.json is \"${pkg.name ?? 'unnamed'}\", not forgemap`\n };\n }\n // Check `.git` only at the forgemap package root, never above it: an installed\n // package under a consumer's node_modules would otherwise inherit that repo's\n // .git and be mislabelled as linked.\n const inGitTree = existsSync(join(pkg.dir, '.git'));\n return {\n kind: inGitTree ? 'linked' : 'release',\n packageRoot: pkg.dir,\n reason: inGitTree\n ? 'runs from a git work tree named forgemap'\n : 'installed forgemap package (no git work tree beside it)'\n };\n}\n\nasync function gatherConfig(\n configFile: string | undefined\n): Promise<ConfigInfo> {\n try {\n const loaded = await loadForgeMapConfig({ configFile });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n return {\n source: loaded.source,\n file: loaded.configFile ?? null,\n root: resolveRoot(loaded.config.root, configDir),\n forges: Object.entries(loaded.config.forges).map(([name, forge]) => ({\n name,\n type: forge.type,\n dir: forge.dir\n })),\n error: null\n };\n } catch (error) {\n // A broken config file must not sink the whole command — the config is one\n // section of the output, not a prerequisite for version/paths/node.\n return {\n source: 'error',\n file: null,\n root: null,\n forges: [],\n error: (error as Error).message\n };\n }\n}\n\nconst SOURCE_LABELS: Record<ConfigSource | 'error', string> = {\n flag: '--config flag',\n env: 'FORGEMAP_CONFIG env',\n 'walk-up': 'walk-up from cwd',\n global: 'global ($XDG_CONFIG_HOME/forgemap)',\n default: 'built-in defaults (no config file found)',\n error: 'failed to load'\n};\n\nconst BUILD_LABELS: Record<BuildKind, string> = {\n linked: 'linked / dev build',\n release: 'installed release',\n unknown: 'unknown'\n};\n\nfunction row(label: string, value: string): string {\n return ` ${colors.dim(label.padEnd(9))} ${value}\\n`;\n}\n\nfunction renderPretty(info: Info): string {\n let out = `${colors.bold('forgemap')} ${colors.cyan(`v${info.version}`)} ${colors.dim(`(${BUILD_LABELS[info.build.kind]})`)}\\n`;\n out += row('build', colors.dim(info.build.reason));\n out += row('binary', info.binary.resolved ?? colors.dim('unknown'));\n if (info.binary.invoked && info.binary.invoked !== info.binary.resolved) {\n out += row('', colors.dim(`via ${info.binary.invoked}`));\n }\n out += row('node', info.node);\n\n out += `\\n${colors.bold('config')}\\n`;\n out += row('source', SOURCE_LABELS[info.config.source]);\n if (info.config.error) {\n out += row('error', colors.red(info.config.error));\n } else {\n out += row('file', info.config.file ?? colors.dim('none'));\n out += row('root', info.config.root ?? colors.dim('unknown'));\n }\n\n out += `\\n${colors.bold('forges')}\\n`;\n if (info.config.forges.length === 0) {\n out += ` ${colors.dim('none')}\\n`;\n } else {\n for (const forge of info.config.forges) {\n out += ` ${colors.cyan(forge.name.padEnd(12))} ${forge.type} ${colors.dim('→')} ${forge.dir}\\n`;\n }\n }\n return out;\n}\n\nexport const infoCommand = defineCommand({\n meta: {\n name: 'info',\n description:\n 'Describe this installation: version, binary path, node, and resolved config'\n },\n args: {\n json: {\n type: 'boolean',\n description: 'Emit a machine-readable JSON report',\n default: false\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const binary = resolveBinary(process.argv[1]);\n const info: Info = {\n version: __APP_VERSION__,\n build: detectBuild(binary.resolved),\n binary,\n node: process.version,\n config: await gatherConfig(args.config)\n };\n\n if (args.json) {\n process.stdout.write(`${JSON.stringify(info, null, 2)}\\n`);\n return;\n }\n process.stdout.write(renderPretty(info));\n }\n});\n\nexport const __test = { resolveBinary, findPackageRoot, detectBuild };\n","import type { ScannedRepo } from './scan.ts';\n\nconst FLAG = '--filter';\n\n/**\n * Shared `--filter` option for the commands that enumerate repos\n * (`status`, `sync`, `list`), so the flag reads identically everywhere.\n */\nexport const filterArg = {\n type: 'string',\n description:\n 'Restrict to repos whose owner or forge name matches. Repeatable; a repo passes if it matches any value.'\n} as const;\n\n/**\n * Recover every `--filter` occurrence from the raw argv.\n *\n * citty (0.2.2) parses through `node:util` `parseArgs` and never sets\n * `multiple: true`, so Node keeps only the **last** value of a repeated option:\n * `--filter a --filter b` reaches `args.filter` as `'b'`, silently dropping\n * `a`. The raw argv is the only place the full list survives.\n */\nexport function collectFilterArgs(rawArgs: string[]): string[] {\n const values: string[] = [];\n for (let i = 0; i < rawArgs.length; i++) {\n const arg = rawArgs[i]!;\n // Everything past `--` is positional, not ours to read.\n if (arg === '--') break;\n if (arg === FLAG) {\n const next = rawArgs[i + 1];\n // A bare trailing `--filter`, or `--filter --json`, has no value.\n if (next !== undefined && !next.startsWith('-')) {\n values.push(next);\n i++;\n }\n continue;\n }\n if (arg.startsWith(`${FLAG}=`)) values.push(arg.slice(FLAG.length + 1));\n }\n return values;\n}\n\n/**\n * Normalize the shapes a filter value arrives in — absent, a single string, or\n * a list — into a list, dropping blanks (`--filter ''`).\n */\nexport function normalizeFilters(\n value: string | string[] | undefined\n): string[] {\n if (value === undefined) return [];\n const values = Array.isArray(value) ? value : [value];\n return values.map((v) => v.trim()).filter((v) => v.length > 0);\n}\n\n/**\n * The filter values for a run: the raw argv wins, since it is the only shape\n * that survives repetition. Fall back to the parsed value when the argv carries\n * no `--filter` at all, which is how the command is driven programmatically\n * (and in tests), where `rawArgs` may be empty.\n */\nexport function resolveFilters(\n rawArgs: string[],\n value: string | string[] | undefined\n): string[] {\n const fromRawArgs = collectFilterArgs(rawArgs);\n return normalizeFilters(fromRawArgs.length > 0 ? fromRawArgs : value);\n}\n\n/**\n * Keep the repos matching any of `filters` (OR-combined). A value matches when\n * it equals the repo's owner or its forge name, compared case-insensitively —\n * forge and owner names are case-preserving but not case-significant. An empty\n * filter list is a no-op, so an unused flag never narrows the output.\n */\nexport function filterRepos(\n repos: ScannedRepo[],\n filters: string[]\n): ScannedRepo[] {\n if (filters.length === 0) return repos;\n const wanted = new Set(filters.map((f) => f.toLowerCase()));\n return repos.filter(\n (r) =>\n wanted.has(r.owner.toLowerCase()) || wanted.has(r.forgeName.toLowerCase())\n );\n}\n","import Fuse, { type IFuseOptions } from 'fuse.js';\nimport type { ScannedRepo } from './scan.ts';\n\n/**\n * The one Fuse configuration every fuzzy lookup shares — `list`, `pick`\n * and the fuzzy slug fallback in `path`/`open`. Keeping it in one place is\n * what makes a query rank identically no matter which command runs it.\n */\nexport const REPO_FUSE_OPTIONS: IFuseOptions<ScannedRepo> = {\n keys: ['slug', 'owner', 'repo'],\n threshold: 0.3,\n ignoreLocation: true\n};\n\nexport function createRepoFuse(repos: ScannedRepo[]): Fuse<ScannedRepo> {\n return new Fuse(repos, REPO_FUSE_OPTIONS);\n}\n\n/** Fuzzy-match `query` against scanned repos, best match first. */\nexport function matchRepos(\n repos: ScannedRepo[],\n query: string,\n limit?: number\n): ScannedRepo[] {\n const fuse = createRepoFuse(repos);\n const results = fuse.search(query, limit ? { limit } : undefined);\n return results.map((r) => r.item);\n}\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors, formatTree } from 'consola/utils';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { filterArg, filterRepos, resolveFilters } from '../repos/filter.ts';\nimport { matchRepos } from '../repos/match.ts';\nimport { type ScannedRepo, scanRepos } from '../repos/scan.ts';\n\ntype Format = 'auto' | 'pretty' | 'path' | 'slug';\n\n// Three levels, like a path: forge → owner → repo.\nfunction renderTree(repos: ScannedRepo[]): string {\n const byForge = new Map<string, Map<string, ScannedRepo[]>>();\n for (const r of repos) {\n let owners = byForge.get(r.forgeName);\n if (!owners) {\n owners = new Map();\n byForge.set(r.forgeName, owners);\n }\n const list = owners.get(r.owner);\n if (list) list.push(r);\n else owners.set(r.owner, [r]);\n }\n\n return formatTree(\n Array.from(byForge, ([forge, owners]) => ({\n text: colors.bold(forge),\n children: Array.from(owners, ([owner, items]) => ({\n text: owner,\n children: items.map((r) => ({\n text: `${colors.cyan(r.repo)} ${colors.dim(r.localPath)}`\n }))\n }))\n }))\n );\n}\n\nexport const listCommand = defineCommand({\n meta: {\n name: 'list',\n description:\n 'List cloned repos; with a query, fuzzy-match by owner/repo and print matches'\n },\n args: {\n query: {\n type: 'positional',\n description:\n 'Optional search term (matched fuzzily against <owner>/<repo>). Omit to list every repo.',\n required: false\n },\n format: {\n type: 'string',\n description:\n 'Output format: auto (default), pretty, path, or slug. auto picks pretty in a TTY, path when piped.',\n default: 'auto'\n },\n filter: filterArg,\n limit: {\n type: 'string',\n description: 'Maximum number of matches to print (default: unlimited)'\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args, rawArgs }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const scanned = await scanRepos({ config: loaded.config, configDir });\n // Narrow before matching, so --limit counts matches within the filtered set.\n const repos = filterRepos(scanned, resolveFilters(rawArgs, args.filter));\n\n const limit = args.limit ? Number.parseInt(args.limit, 10) : undefined;\n // No query lists everything: Fuse treats an empty query as \"match all\".\n const query = args.query ?? '';\n const items = matchRepos(repos, query, limit);\n\n const allowed: Format[] = ['auto', 'pretty', 'path', 'slug'];\n if (!allowed.includes(args.format as Format)) {\n consola.error(\n `Invalid --format value \"${args.format}\". Allowed: ${allowed.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n const requested = args.format as Format;\n const format: Exclude<Format, 'auto'> =\n requested === 'auto'\n ? process.stdout.isTTY\n ? 'pretty'\n : 'path'\n : requested;\n\n if (items.length === 0) {\n if (format === 'pretty') {\n consola.info(query ? `No matches for \"${query}\".` : 'No repos found.');\n }\n return;\n }\n\n if (format === 'pretty') {\n process.stdout.write(`${renderTree(items)}\\n`);\n return;\n }\n\n for (const item of items) {\n process.stdout.write(\n `${format === 'slug' ? item.slug : item.localPath}\\n`\n );\n }\n }\n});\n","import consola from 'consola';\nimport { colors } from 'consola/utils';\nimport type { ForgeMapConfig } from '../config/schema.ts';\nimport { matchRepos } from '../repos/match.ts';\nimport { canPrompt, promptRepoChoice } from '../repos/picker.ts';\nimport { type ScannedRepo, scanRepos } from '../repos/scan.ts';\nimport { looksLikeSlug, parseSlug } from './parse.ts';\nimport { resolveSlug } from './resolve.ts';\n\nexport interface LocateOptions {\n config: ForgeMapConfig;\n configDir: string;\n /** Pre-scanned repos. Scanned on demand when omitted. */\n repos?: ScannedRepo[];\n}\n\nexport type LocateOutcome =\n /** Input was a strict slug — resolved by layout, cloned or not. */\n | { kind: 'slug'; localPath: string }\n /** Fuzzy query hit exactly one cloned repo. */\n | { kind: 'match'; localPath: string; repo: ScannedRepo }\n /** Fuzzy query hit several cloned repos. */\n | { kind: 'ambiguous'; query: string; candidates: ScannedRepo[] }\n /** Fuzzy query hit nothing. */\n | { kind: 'none'; query: string };\n\n/**\n * Turn user input into a repo location.\n *\n * A strict slug is resolved from the configured layout and never consults the\n * disk — so an explicit `owner/repo` always wins over any fuzzy match, and\n * still resolves for a repo that isn't cloned yet. Only input that cannot be a\n * slug at all falls back to fuzzy-matching the cloned repos.\n *\n * Throws for malformed *slugs* (`foo/bar/baz`, a bad URL, empty input) — those\n * are mistakes to report, not queries to guess at.\n */\nexport async function locateRepo(\n input: string,\n options: LocateOptions\n): Promise<LocateOutcome> {\n const { config, configDir } = options;\n\n if (!input.trim() || looksLikeSlug(input)) {\n const resolved = resolveSlug(parseSlug(input), { config, configDir });\n return { kind: 'slug', localPath: resolved.localPath };\n }\n\n const repos = options.repos ?? (await scanRepos({ config, configDir }));\n const candidates = matchRepos(repos, input);\n\n if (candidates.length === 0) return { kind: 'none', query: input };\n if (candidates.length === 1) {\n return {\n kind: 'match',\n localPath: candidates[0]!.localPath,\n repo: candidates[0]!\n };\n }\n return { kind: 'ambiguous', query: input, candidates };\n}\n\n/**\n * {@link locateRepo} plus the interactive/diagnostic layer shared by `path`\n * and `open`: prompt on an ambiguous query when there is a TTY to prompt on,\n * otherwise explain and fail. Returns null when nothing was resolved — the\n * caller sets the exit code.\n *\n * Every diagnostic goes to stderr: `$(forgemap path <q>)` captures stdout, and\n * a hint leaking into that capture would be read as a path.\n */\nexport async function resolveRepoPath(\n input: string,\n options: LocateOptions\n): Promise<string | null> {\n const outcome = await locateRepo(input, options);\n\n switch (outcome.kind) {\n case 'slug':\n case 'match':\n return outcome.localPath;\n\n case 'none':\n consola.error(`No cloned repo matches \"${outcome.query}\".`);\n process.stderr.write(\n `${colors.dim('Pass an explicit <owner>/<repo> for a repo that is not cloned yet.')}\\n`\n );\n return null;\n\n case 'ambiguous': {\n if (canPrompt()) {\n return (await promptRepoChoice(outcome.candidates)) ?? null;\n }\n consola.error(\n `\"${outcome.query}\" matches ${outcome.candidates.length} cloned repos:`\n );\n for (const c of outcome.candidates) {\n process.stderr.write(\n ` ${colors.cyan(`${c.forgeName}:${c.slug}`)} ${colors.dim(c.localPath)}\\n`\n );\n }\n process.stderr.write(\n `${colors.dim('Narrow the query, pass an explicit <owner>/<repo>, or run `forgemap pick` to choose interactively.')}\\n`\n );\n return null;\n }\n }\n}\n","import { spawn } from 'node:child_process';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { resolveRepoPath } from '../slug/locate.ts';\n\ninterface OpenInvocation {\n cmd: string;\n args: string[];\n}\n\nfunction platformOpen(localPath: string): OpenInvocation {\n const distro = process.env.WSL_DISTRO_NAME;\n if (distro) {\n const winPath = `\\\\\\\\wsl$\\\\${distro}${localPath.replaceAll('/', '\\\\')}`;\n return { cmd: 'explorer.exe', args: [winPath] };\n }\n if (process.platform === 'darwin') {\n return { cmd: 'open', args: [localPath] };\n }\n return { cmd: 'xdg-open', args: [localPath] };\n}\n\nexport const openCommand = defineCommand({\n meta: {\n name: 'open',\n description:\n 'Open a repo in the OS file manager (Explorer on WSL, Finder on macOS, xdg-open elsewhere)'\n },\n args: {\n slug: {\n type: 'positional',\n description:\n 'owner/repo, forge:owner/repo, full URL, or a fuzzy query matched against cloned repos',\n required: true\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const localPath = await resolveRepoPath(args.slug, {\n config: loaded.config,\n configDir\n });\n if (!localPath) {\n process.exitCode = 1;\n return;\n }\n\n const { cmd, args: cmdArgs } = platformOpen(localPath);\n consola.info(`Opening ${localPath}`);\n\n const child = spawn(cmd, cmdArgs, {\n stdio: 'ignore',\n detached: true\n });\n child.on('error', (error: NodeJS.ErrnoException) => {\n if (error.code === 'ENOENT') {\n consola.error(\n `Could not find \\`${cmd}\\`. Install it (or open the path manually).`\n );\n process.exitCode = 1;\n } else {\n consola.error(error.message);\n process.exitCode = 1;\n }\n });\n child.unref();\n }\n});\n","import { defineCommand } from 'citty';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { resolveRepoPath } from '../slug/locate.ts';\n\nexport const pathCommand = defineCommand({\n meta: {\n name: 'path',\n description: 'Print the local path where a repo lives (or would live)'\n },\n args: {\n slug: {\n type: 'positional',\n description:\n 'owner/repo, forge:owner/repo, full URL, or a fuzzy query matched against cloned repos',\n required: true\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const localPath = await resolveRepoPath(args.slug, {\n config: loaded.config,\n configDir\n });\n if (!localPath) {\n process.exitCode = 1;\n return;\n }\n process.stdout.write(`${localPath}\\n`);\n }\n});\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { matchRepos } from '../repos/match.ts';\nimport { canPrompt, promptRepoChoice } from '../repos/picker.ts';\nimport { type ScannedRepo, scanRepos } from '../repos/scan.ts';\n\nexport const pickCommand = defineCommand({\n meta: {\n name: 'pick',\n description:\n 'Interactively pick a cloned repo from the configured layout and print its path'\n },\n args: {\n query: {\n type: 'positional',\n description: 'Optional fuzzy filter applied before showing the picker',\n required: false\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const all = await scanRepos({ config: loaded.config, configDir });\n\n const candidates: ScannedRepo[] = args.query\n ? matchRepos(all, args.query)\n : all;\n\n if (candidates.length === 0) {\n consola.error(\n args.query\n ? `No repos match \"${args.query}\".`\n : 'No repos found under the configured root.'\n );\n process.exitCode = 1;\n return;\n }\n\n if (candidates.length === 1) {\n process.stdout.write(`${candidates[0]!.localPath}\\n`);\n return;\n }\n\n if (!canPrompt()) {\n consola.error(\n 'pick requires an interactive terminal. Use `forgemap list` for non-interactive output.'\n );\n process.exitCode = 1;\n return;\n }\n\n const choice = await promptRepoChoice(candidates);\n if (choice) {\n process.stdout.write(`${choice}\\n`);\n }\n }\n});\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport {\n type Shell,\n SUPPORTED_SHELLS as SUPPORTED,\n detectShell,\n installRcBlock\n} from '../utils/shell.ts';\n\n/** Append (idempotently) a loader that, plus completion, sets up the shell so\n * the user only has to re-source their rc file. */\nasync function install(shell: Shell, name: string): Promise<void> {\n const nameArg = name && name !== 'forgemap' ? ` --name ${name}` : '';\n const loaders =\n shell === 'fish'\n ? [\n `forgemap shell-init fish${nameArg} | source`,\n 'forgemap completion fish | source'\n ]\n : [\n `eval \"$(forgemap shell-init ${shell}${nameArg})\"`,\n `eval \"$(forgemap completion ${shell})\"`\n ];\n // 'shell-init' is the legacy label (before this block also loaded\n // completion) — strip it so a re-install never leaves a duplicate.\n const { status, rcFile } = await installRcBlock(shell, 'shell', loaders, [\n 'shell-init'\n ]);\n if (status === 'present') {\n consola.info(`forgemap shell integration already present in ${rcFile}.`);\n return;\n }\n const verb = status === 'updated' ? 'Updated' : 'Added';\n consola.success(\n `${verb} forgemap shell integration (cd + completion) in ${rcFile}.`\n );\n consola.info(\n `Run \\`source ${rcFile}\\` or restart your shell to activate it.`\n );\n}\n\nfunction renderPosix(name: string): string {\n return `# forgemap shell integration — drop into your ~/.zshrc / ~/.bashrc:\n# eval \"$(forgemap shell-init)\"\n#\n# Wraps the forgemap binary so that \\`${name} cd <slug>\\` actually changes\n# directory in this shell. All other subcommands fall through unchanged.\n\n${name}() {\n if [ \"$1\" = \"cd\" ]; then\n shift\n local target\n if [ \"$#\" -eq 0 ]; then\n target=$(command forgemap pick) || return $?\n else\n local matches\n matches=$(command forgemap list \"$1\" --format path)\n local count\n count=$(printf '%s' \"$matches\" | grep -c '^/' || true)\n if [ \"$count\" = \"1\" ]; then\n target=\"$matches\"\n elif [ \"$count\" = \"0\" ]; then\n echo \"forgemap cd: no match for $1\" >&2\n return 1\n else\n target=$(command forgemap pick \"$1\") || return $?\n fi\n fi\n [ -n \"$target\" ] && builtin cd \"$target\"\n return\n fi\n command forgemap \"$@\"\n}\n`;\n}\n\nfunction renderFish(name: string): string {\n return `# forgemap shell integration — drop into your ~/.config/fish/config.fish:\n# forgemap shell-init fish | source\n\nfunction ${name} --description \"forgemap with cd interception\"\n if test (count $argv) -ge 1 -a \"$argv[1]\" = \"cd\"\n set --erase argv[1]\n set target \"\"\n if test (count $argv) -eq 0\n set target (command forgemap pick); or return $status\n else\n set matches (command forgemap list $argv[1] --format path)\n set count (count $matches)\n if test $count -eq 1\n set target $matches[1]\n else if test $count -eq 0\n echo \"forgemap cd: no match for $argv[1]\" >&2\n return 1\n else\n set target (command forgemap pick $argv[1]); or return $status\n end\n end\n test -n \"$target\"; and builtin cd $target\n return\n end\n command forgemap $argv\nend\n`;\n}\n\nexport const shellInitCommand = defineCommand({\n meta: {\n name: 'shell-init',\n description:\n 'Print (or --install) a shell wrapper that adds `forgemap cd <slug>` as a real cd. Source it via `eval \"$(forgemap shell-init)\"`.'\n },\n args: {\n shell: {\n type: 'positional',\n description: `Shell flavor (${SUPPORTED.join(', ')}). Auto-detected from $SHELL if omitted.`,\n required: false\n },\n name: {\n type: 'string',\n description: 'Name of the generated wrapper function (default: forgemap)',\n default: 'forgemap'\n },\n install: {\n type: 'boolean',\n description:\n \"Append the loader to your shell's rc file (idempotent) instead of printing\",\n default: false\n }\n },\n async run({ args }) {\n const requested = (args.shell ?? detectShell()) as Shell;\n if (!SUPPORTED.includes(requested)) {\n consola.error(\n `Unsupported shell \"${requested}\". Supported: ${SUPPORTED.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n const name = args.name || 'forgemap';\n if (args.install) {\n await install(requested, name);\n return;\n }\n const out = requested === 'fish' ? renderFish(name) : renderPosix(name);\n process.stdout.write(out);\n }\n});\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors, formatTree } from 'consola/utils';\nimport Fuse from 'fuse.js';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { scanReposCached } from '../repos/cache.ts';\nimport { filterArg, filterRepos, resolveFilters } from '../repos/filter.ts';\nimport { getRepoStatus, type RepoStatus } from '../repos/git.ts';\nimport type { ScannedRepo } from '../repos/scan.ts';\n\ninterface Row {\n repo: ScannedRepo;\n status: RepoStatus | null;\n error?: string;\n}\n\nfunction statusLine(row: Row): string {\n if (row.error || !row.status) {\n return `${colors.cyan(row.repo.repo)} ${colors.red(`error: ${row.error ?? 'unknown'}`)}`;\n }\n const s = row.status;\n const parts: string[] = [colors.cyan(row.repo.repo)];\n const aheadBehind: string[] = [];\n if (s.ahead > 0) aheadBehind.push(colors.green(`↑${s.ahead}`));\n if (s.behind > 0) aheadBehind.push(colors.yellow(`↓${s.behind}`));\n if (aheadBehind.length > 0) parts.push(aheadBehind.join(' '));\n parts.push(s.dirty ? colors.red('●') : colors.green('✓'));\n // Stashed work is invisible to every other marker here — surface it before\n // it matters (e.g. before `cleanup` considers the repo).\n if (s.stashes > 0) parts.push(colors.yellow(`⚑${s.stashes}`));\n parts.push(colors.gray(s.branch));\n if (s.lastCommit) {\n parts.push(colors.dim(`${s.lastCommit.sha} ${s.lastCommit.relativeDate}`));\n }\n return parts.join(' ');\n}\n\n// Three levels, like a path: forge → owner → repo.\nfunction renderTree(rows: Row[]): string {\n const byForge = new Map<string, Map<string, Row[]>>();\n for (const row of rows) {\n let owners = byForge.get(row.repo.forgeName);\n if (!owners) {\n owners = new Map();\n byForge.set(row.repo.forgeName, owners);\n }\n const list = owners.get(row.repo.owner);\n if (list) list.push(row);\n else owners.set(row.repo.owner, [row]);\n }\n return formatTree(\n Array.from(byForge, ([forge, owners]) => ({\n text: colors.bold(forge),\n children: Array.from(owners, ([owner, items]) => ({\n text: owner,\n children: items.map((row) => ({ text: statusLine(row) }))\n }))\n }))\n );\n}\n\nconst ALLOWED_FORMATS = ['pretty', 'json'];\n\nexport const statusCommand = defineCommand({\n meta: {\n name: 'status',\n description: 'Show branch, dirty, ahead/behind, and last commit per repo'\n },\n args: {\n format: {\n type: 'string',\n description: 'Output format: pretty (default) or json',\n default: 'pretty'\n },\n forge: {\n type: 'string',\n description: 'Restrict to a single forge alias'\n },\n filter: filterArg,\n query: {\n type: 'string',\n description: 'Fuzzy filter against <owner>/<repo>'\n },\n cache: {\n type: 'boolean',\n description: 'Use the scanned-repos cache',\n negativeDescription: 'Skip the scanned-repos cache',\n default: true\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args, rawArgs }) {\n if (!ALLOWED_FORMATS.includes(args.format)) {\n consola.error(\n `Invalid --format value \"${args.format}\". Allowed: ${ALLOWED_FORMATS.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n let repos = await scanReposCached({\n config: loaded.config,\n configDir,\n useCache: args.cache\n });\n\n if (args.forge) {\n repos = repos.filter((r) => r.forgeName === args.forge);\n }\n repos = filterRepos(repos, resolveFilters(rawArgs, args.filter));\n if (args.query) {\n const fuse = new Fuse(repos, {\n keys: ['slug', 'owner', 'repo'],\n threshold: 0.3,\n ignoreLocation: true\n });\n repos = fuse.search(args.query).map((r) => r.item);\n }\n\n const rows: Row[] = await Promise.all(\n repos.map(async (repo) => {\n try {\n return { repo, status: await getRepoStatus(repo.localPath) };\n } catch (error) {\n return { repo, status: null, error: (error as Error).message };\n }\n })\n );\n\n if (args.format === 'json') {\n process.stdout.write(\n `${JSON.stringify(\n rows.map((r) => ({\n forge: r.repo.forgeName,\n owner: r.repo.owner,\n repo: r.repo.repo,\n localPath: r.repo.localPath,\n status: r.status,\n error: r.error ?? null\n })),\n null,\n 2\n )}\\n`\n );\n return;\n }\n\n if (rows.length === 0) {\n consola.info('No repos to report on.');\n return;\n }\n process.stdout.write(`${renderTree(rows)}\\n`);\n }\n});\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors } from 'consola/utils';\nimport Fuse from 'fuse.js';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport { scanReposCached } from '../repos/cache.ts';\nimport { filterArg, filterRepos, resolveFilters } from '../repos/filter.ts';\nimport { fetchRepo, isClean, pullRepo } from '../repos/git.ts';\nimport type { ScannedRepo } from '../repos/scan.ts';\n\ninterface SyncOutcome {\n repo: ScannedRepo;\n status: 'synced' | 'skipped' | 'failed';\n message?: string;\n}\n\nasync function runWithConcurrency<T>(\n items: T[],\n limit: number,\n task: (item: T) => Promise<void>\n): Promise<void> {\n const queue = [...items];\n const workers = Array.from(\n { length: Math.min(limit, queue.length) },\n async () => {\n while (queue.length > 0) {\n const next = queue.shift();\n if (!next) return;\n await task(next);\n }\n }\n );\n await Promise.all(workers);\n}\n\nexport const syncCommand = defineCommand({\n meta: {\n name: 'sync',\n description:\n 'Run git fetch (or --pull) across every cloned repo, in parallel'\n },\n args: {\n pull: {\n type: 'boolean',\n description:\n 'Pull --ff-only instead of fetch. Dirty working trees are skipped.',\n default: false\n },\n concurrency: {\n type: 'string',\n description: 'Number of parallel workers (default: 4)'\n },\n sequential: {\n type: 'boolean',\n description: 'Run one repo at a time (overrides --concurrency)',\n default: false\n },\n forge: {\n type: 'string',\n description: 'Restrict to a single forge alias'\n },\n filter: filterArg,\n query: {\n type: 'string',\n description: 'Fuzzy filter against <owner>/<repo>'\n },\n cache: {\n type: 'boolean',\n description: 'Use the scanned-repos cache',\n negativeDescription: 'Skip the scanned-repos cache',\n default: true\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args, rawArgs }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n let repos = await scanReposCached({\n config: loaded.config,\n configDir,\n useCache: args.cache\n });\n\n if (args.forge) {\n repos = repos.filter((r) => r.forgeName === args.forge);\n }\n repos = filterRepos(repos, resolveFilters(rawArgs, args.filter));\n if (args.query) {\n const fuse = new Fuse(repos, {\n keys: ['slug', 'owner', 'repo'],\n threshold: 0.3,\n ignoreLocation: true\n });\n repos = fuse.search(args.query).map((r) => r.item);\n }\n\n if (repos.length === 0) {\n consola.info('Nothing to sync.');\n return;\n }\n\n const concurrency = args.sequential\n ? 1\n : args.concurrency\n ? Math.max(1, Number.parseInt(args.concurrency, 10))\n : 4;\n\n consola.info(\n `Syncing ${repos.length} repo(s) — ${args.pull ? 'pull' : 'fetch'}, concurrency ${concurrency}`\n );\n\n const outcomes: SyncOutcome[] = [];\n await runWithConcurrency(repos, concurrency, async (repo) => {\n try {\n if (args.pull && !(await isClean(repo.localPath))) {\n outcomes.push({\n repo,\n status: 'skipped',\n message: 'dirty working tree'\n });\n consola.warn(`${colors.dim(repo.slug)} — skipped (dirty)`);\n return;\n }\n const result = args.pull\n ? await pullRepo(repo.localPath)\n : await fetchRepo(repo.localPath);\n if (result.code === 0) {\n outcomes.push({ repo, status: 'synced' });\n consola.success(colors.dim(repo.slug));\n } else {\n const message = result.timedOut\n ? 'timed out (remote unreachable)'\n : (result.stderr || result.stdout).trim().split('\\n')[0] ||\n `git exited with code ${result.code}`;\n outcomes.push({\n repo,\n status: 'failed',\n message\n });\n consola.fail(\n `${colors.dim(repo.slug)} — ${outcomes.at(-1)?.message}`\n );\n }\n } catch (error) {\n outcomes.push({\n repo,\n status: 'failed',\n message: (error as Error).message\n });\n consola.fail(`${colors.dim(repo.slug)} — ${(error as Error).message}`);\n }\n });\n\n const synced = outcomes.filter((o) => o.status === 'synced').length;\n const skipped = outcomes.filter((o) => o.status === 'skipped').length;\n const failed = outcomes.filter((o) => o.status === 'failed').length;\n consola.info(\n `Done — ${colors.green(`${synced} synced`)}, ${colors.yellow(`${skipped} skipped`)}, ${colors.red(`${failed} failed`)}`\n );\n if (failed > 0) {\n process.exitCode = 1;\n }\n }\n});\n","import { access } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors } from 'consola/utils';\nimport { dirname } from 'pathe';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport type { ForgeConfig, ForgeMapConfig } from '../config/schema.ts';\nimport { resolveRoot } from '../utils/path.ts';\nimport { execCapture, hasCommand } from '../utils/exec.ts';\n\ntype CheckSeverity = 'ok' | 'warn' | 'fail';\n\ninterface Check {\n name: string;\n severity: CheckSeverity;\n message: string;\n}\n\nconst KNOWN_TYPES = new Set(['github', 'gitlab', 'gitea', 'codeberg', 'git']);\n\nfunction validateForge(name: string, forge: ForgeConfig): Check {\n if (!KNOWN_TYPES.has(forge.type)) {\n return {\n name: `forge \"${name}\"`,\n severity: 'fail',\n message: `unknown type \"${forge.type}\"`\n };\n }\n if (!forge.host?.trim()) {\n return {\n name: `forge \"${name}\"`,\n severity: 'fail',\n message: 'host is empty'\n };\n }\n if (!forge.dir?.trim()) {\n return {\n name: `forge \"${name}\"`,\n severity: 'fail',\n message: 'dir is empty'\n };\n }\n return {\n name: `forge \"${name}\"`,\n severity: 'ok',\n message: `${forge.type} at ${forge.host}`\n };\n}\n\nasync function runChecks(\n config: ForgeMapConfig,\n configDir: string\n): Promise<Check[]> {\n const checks: Check[] = [];\n\n for (const [name, forge] of Object.entries(config.forges)) {\n checks.push(validateForge(name, forge));\n }\n\n checks.push(\n config.forges[config.defaultForge]\n ? {\n name: 'defaultForge',\n severity: 'ok',\n message: `→ ${config.defaultForge}`\n }\n : {\n name: 'defaultForge',\n severity: 'fail',\n message: `\"${config.defaultForge}\" is not in forges`\n }\n );\n\n const root = resolveRoot(config.root, configDir);\n try {\n await access(root);\n checks.push({\n name: 'root directory',\n severity: 'ok',\n message: root\n });\n } catch {\n checks.push({\n name: 'root directory',\n severity: 'fail',\n message: `${root} does not exist (mkdir -p it or fix root in config)`\n });\n }\n\n const types = new Set(Object.values(config.forges).map((f) => f.type));\n const needsGit = types.has('git') || types.size > 0;\n const needsGh = types.has('github');\n\n if (needsGit) {\n checks.push(\n (await hasCommand('git'))\n ? { name: 'git CLI', severity: 'ok', message: 'on PATH' }\n : {\n name: 'git CLI',\n severity: 'fail',\n message: 'install from https://git-scm.com/'\n }\n );\n }\n\n if (needsGh) {\n if (await hasCommand('gh')) {\n checks.push({ name: 'gh CLI', severity: 'ok', message: 'on PATH' });\n const auth = await execCapture('gh', ['auth', 'status']);\n checks.push(\n auth.code === 0\n ? { name: 'gh auth', severity: 'ok', message: 'authenticated' }\n : {\n name: 'gh auth',\n severity: 'warn',\n message: 'not logged in — run `gh auth login`'\n }\n );\n } else {\n checks.push({\n name: 'gh CLI',\n severity: 'fail',\n message: 'install from https://cli.github.com/'\n });\n }\n }\n\n return checks;\n}\n\nfunction severitySymbol(severity: CheckSeverity): string {\n if (severity === 'ok') return colors.green('✓');\n if (severity === 'warn') return colors.yellow('!');\n return colors.red('✗');\n}\n\nexport const validateCommand = defineCommand({\n meta: {\n name: 'validate',\n description:\n 'Preflight: check the config schema, required CLI tools, and root directory'\n },\n args: {\n json: {\n type: 'boolean',\n description: 'Emit a machine-readable JSON report',\n default: false\n },\n config: {\n type: 'string',\n description: 'Path to forgemap.config.ts (overrides walk-up discovery)'\n }\n },\n async run({ args }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const checks = await runChecks(loaded.config, configDir);\n const ok = checks.every((c) => c.severity !== 'fail');\n\n if (args.json) {\n process.stdout.write(`${JSON.stringify({ ok, checks }, null, 2)}\\n`);\n } else {\n for (const c of checks) {\n process.stdout.write(\n `${severitySymbol(c.severity)} ${c.name.padEnd(22)} ${colors.dim(c.message)}\\n`\n );\n }\n process.stdout.write(\n `\\n${ok ? colors.green('All checks passed.') : colors.red('Validation failed.')}\\n`\n );\n }\n\n if (!ok) {\n process.exitCode = 1;\n return;\n }\n if (!loaded.configFile) {\n consola.warn(\n 'No forgemap.config.ts found — using built-in defaults. Run `forgemap config init` to materialize one.'\n );\n }\n }\n});\n","import { type ArgsDef, type CommandDef, defineCommand } from 'citty';\nimport consola from 'consola';\nimport {\n type Shell,\n SUPPORTED_SHELLS as SUPPORTED,\n detectShell,\n installRcBlock\n} from '../utils/shell.ts';\nimport { cdCommand } from './cd.ts';\nimport { cleanupCommand } from './cleanup.ts';\nimport { cloneCommand } from './clone.ts';\nimport { configCommand } from './config/index.ts';\nimport { deleteCommand } from './delete.ts';\nimport { forgeCommand } from './forge/index.ts';\nimport { importCommand } from './import.ts';\nimport { infoCommand } from './info.ts';\nimport { listCommand } from './list.ts';\nimport { openCommand } from './open.ts';\nimport { pathCommand } from './path.ts';\nimport { pickCommand } from './pick.ts';\nimport { shellInitCommand } from './shell-init.ts';\nimport { statusCommand } from './status.ts';\nimport { syncCommand } from './sync.ts';\nimport { validateCommand } from './validate.ts';\n\n// Commands whose depth-2 positional is a repo slug: these complete against the\n// live `forgemap list --format slug` output (the one dynamic value source).\nconst SLUG_COMMANDS = ['clone', 'cd', 'path', 'open', 'list', 'pick', 'delete'];\n\n// Fixed value sets a command validates internally. citty's arg metadata carries\n// no enum options for these — they are declared `type: 'string'` and checked in\n// each command's `run()` — so the value lists are curated here, keyed by\n// subcommand then flag, sitting next to the flags they annotate. Flag *names*\n// are derived from the definitions below and need no upkeep; only these static\n// value sets do.\nconst STATIC_FLAG_VALUES: Record<string, Record<string, string[]>> = {\n list: { '--format': ['auto', 'pretty', 'path', 'slug'] },\n status: { '--format': ['pretty', 'json'] },\n import: { '--format': ['pretty', 'json'], '--type': ['forgemap'] }\n};\n\n// Commands whose leading positional is a shell flavor (completed statically\n// from the supported-shells list rather than hardcoded here).\nconst SHELL_POSITIONAL = new Set(['completion', 'shell-init']);\n\n// Commands in the registry have heterogeneous arg shapes; `CommandDef<any>` is\n// how citty itself types such collections (see its `SubCommandsDef`).\ntype AnyCommand = CommandDef<any>;\n\ninterface CommandSpec {\n name: string;\n /** Flag names (`--foo`, plus `--no-foo` for negatable booleans). */\n flags: string[];\n /** Static value sets for flags that take a fixed enum (e.g. `--format`). */\n flagValues: Record<string, string[]>;\n /** Static values for the leading positional (shell flavors), if any. */\n positionalValues: string[];\n /** Whether the leading positional completes against repo slugs. */\n slugs: boolean;\n}\n\n/** Every forgemap command declares `args` as a plain object literal (or omits\n * it, like `config`), never a thunk — so no `Resolvable` unwrapping is needed. */\nfunction argsOf(cmd: AnyCommand): ArgsDef {\n return (cmd.args ?? {}) as ArgsDef;\n}\n\n/** Flag names a command exposes, derived from its `defineCommand` args so a new\n * flag surfaces in completion automatically. Positionals are handled\n * separately; negatable booleans (those with a `negativeDescription`) also get\n * their `--no-<flag>` form. */\nfunction flagsOf(cmd: AnyCommand): string[] {\n const flags: string[] = [];\n for (const [name, def] of Object.entries(argsOf(cmd))) {\n if (def.type === 'positional') continue;\n flags.push(`--${name}`);\n if (def.type === 'boolean' && def.negativeDescription) {\n flags.push(`--no-${name}`);\n }\n }\n return flags;\n}\n\n/** The ordered subcommand registry, mirroring `rootCommand.subCommands` in\n * cli.ts. It is kept here rather than imported from cli.ts because that would\n * form a cycle (cli → completion → cli). Built lazily so the self-reference to\n * `completionCommand` resolves after the module finishes initializing. */\nfunction commandSpecs(): CommandSpec[] {\n const registry: Array<readonly [string, AnyCommand]> = [\n ['clone', cloneCommand],\n ['import', importCommand],\n ['cleanup', cleanupCommand],\n ['delete', deleteCommand],\n ['cd', cdCommand],\n ['path', pathCommand],\n ['open', openCommand],\n ['list', listCommand],\n ['pick', pickCommand],\n ['status', statusCommand],\n ['sync', syncCommand],\n ['validate', validateCommand],\n ['info', infoCommand],\n ['completion', completionCommand],\n ['shell-init', shellInitCommand],\n ['config', configCommand],\n ['forge', forgeCommand]\n ];\n return registry.map(([name, cmd]) => ({\n name,\n flags: flagsOf(cmd),\n flagValues: STATIC_FLAG_VALUES[name] ?? {},\n positionalValues: SHELL_POSITIONAL.has(name) ? [...SUPPORTED] : [],\n slugs: SLUG_COMMANDS.includes(name)\n }));\n}\n\nfunction flagValuePairs(\n specs: CommandSpec[]\n): Array<[string, string, string[]]> {\n return specs.flatMap((s) =>\n Object.entries(s.flagValues).map(\n ([flag, values]) => [s.name, flag, values] as [string, string, string[]]\n )\n );\n}\n\nfunction renderBash(specs: CommandSpec[]): string {\n const names = specs.map((s) => s.name).join(' ');\n\n const valueArms = flagValuePairs(specs)\n .map(\n ([cmd, flag, values]) =>\n ` ${cmd}:${flag}) COMPREPLY=( $(compgen -W \"${values.join(' ')}\" -- \"$cur\") ); return ;;`\n )\n .join('\\n');\n\n const flagArms = specs\n .filter((s) => s.flags.length > 0)\n .map((s) => ` ${s.name}) flags=\"${s.flags.join(' ')}\" ;;`)\n .join('\\n');\n\n const slugCmds = specs.filter((s) => s.slugs).map((s) => s.name);\n const positionalArms = [\n slugCmds.length > 0\n ? ` ${slugCmds.join('|')})\n local slugs\n slugs=$(forgemap list --format slug 2>/dev/null)\n COMPREPLY=( $(compgen -W \"$slugs\" -- \"$cur\") )\n ;;`\n : '',\n ...specs\n .filter((s) => s.positionalValues.length > 0)\n .map(\n (s) =>\n ` ${s.name}) COMPREPLY=( $(compgen -W \"${s.positionalValues.join(' ')}\" -- \"$cur\") ) ;;`\n )\n ]\n .filter(Boolean)\n .join('\\n');\n\n return `# forgemap bash completion — drop into your ~/.bashrc:\n# eval \"$(forgemap completion bash)\"\n_forgemap_completion() {\n local cur prev cmd flags\n COMPREPLY=()\n cur=\"\\${COMP_WORDS[COMP_CWORD]}\"\n prev=\"\\${COMP_WORDS[COMP_CWORD-1]}\"\n cmd=\"\\${COMP_WORDS[1]}\"\n\n if [ \"$COMP_CWORD\" = \"1\" ]; then\n COMPREPLY=( $(compgen -W \"${names}\" -- \"$cur\") )\n return\n fi\n\n # Values for flags with a fixed set (e.g. --format), keyed by \"<cmd>:<flag>\".\n case \"$cmd:$prev\" in\n${valueArms}\n esac\n\n # Flag names for the current subcommand.\n if [[ \"$cur\" == -* ]]; then\n case \"$cmd\" in\n${flagArms}\n esac\n COMPREPLY=( $(compgen -W \"$flags\" -- \"$cur\") )\n return\n fi\n\n # Positional values (repo slugs, or a shell name).\n case \"$cmd\" in\n${positionalArms}\n esac\n}\ncomplete -F _forgemap_completion forgemap\n`;\n}\n\nfunction renderZsh(specs: CommandSpec[]): string {\n const subcommands = specs.map((s) => `'${s.name}'`).join(' ');\n\n const valueArms = flagValuePairs(specs)\n .map(\n ([cmd, flag, values]) =>\n ` ${cmd}:${flag}) compadd ${values.join(' ')}; return ;;`\n )\n .join('\\n');\n\n const flagArms = specs\n .filter((s) => s.flags.length > 0)\n .map((s) => ` ${s.name}) compadd -- ${s.flags.join(' ')}; return ;;`)\n .join('\\n');\n\n const slugCmds = specs\n .filter((s) => s.slugs)\n .map((s) => s.name)\n .join('|');\n const shellArms = specs\n .filter((s) => s.positionalValues.length > 0)\n .map((s) => ` ${s.name}) compadd ${s.positionalValues.join(' ')} ;;`)\n .join('\\n');\n\n return `# forgemap zsh completion — drop into your ~/.zshrc:\n# eval \"$(forgemap completion zsh)\"\n_forgemap() {\n local -a subcommands\n subcommands=(${subcommands})\n local cmd=\"\\${words[2]}\"\n local prev=\"\\${words[CURRENT-1]}\"\n local cur=\"\\${words[CURRENT]}\"\n\n if (( CURRENT == 2 )); then\n _describe 'forgemap subcommand' subcommands\n return\n fi\n\n # Values for flags with a fixed set (e.g. --format), keyed by \"<cmd>:<flag>\".\n case \"$cmd:$prev\" in\n${valueArms}\n esac\n\n # Flag names for the current subcommand.\n if [[ \"$cur\" == -* ]]; then\n case \"$cmd\" in\n${flagArms}\n esac\n return\n fi\n\n # Positional values (repo slugs, or a shell name).\n case \"$cmd\" in\n ${slugCmds})\n local -a slugs\n slugs=(\"\\${(@f)$(forgemap list --format slug 2>/dev/null)}\")\n _describe 'slug' slugs\n ;;\n${shellArms}\n esac\n}\ncompdef _forgemap forgemap\n`;\n}\n\nfunction renderFish(specs: CommandSpec[]): string {\n const names = specs.map((s) => s.name).join(' ');\n\n const flagLines = specs\n .flatMap((s) =>\n s.flags.map((flag) => {\n const long = flag.replace(/^--/, '');\n const values = s.flagValues[flag];\n const valuePart = values ? ` -x -a '${values.join(' ')}'` : '';\n return `complete -c forgemap -n '__fish_seen_subcommand_from ${s.name}' -l ${long}${valuePart}`;\n })\n )\n .join('\\n');\n\n const shellCmds = specs.filter((s) => s.positionalValues.length > 0);\n const shellCmdsList = shellCmds.map((s) => `\"${s.name}\"`).join(' ');\n // Both shell-positional commands share the supported-shells value set.\n const shellValues = shellCmds[0]?.positionalValues.join(' ') ?? '';\n\n const slugCmdsList = specs\n .filter((s) => s.slugs)\n .map((s) => `\"${s.name}\"`)\n .join(' ');\n\n return `# forgemap fish completion — drop into your ~/.config/fish/config.fish:\n# forgemap completion fish | source\n\n# Subcommands (depth 1).\ncomplete -c forgemap -f -n '__fish_use_subcommand' -a '${names}'\n\n# Flags per subcommand (with fixed value sets where applicable).\n${flagLines}\n\n# Shell flavor for completion / shell-init (depth 2).\nfunction __forgemap_needs_shell\n set -l tokens (commandline -opc)\n set -l shell_cmds ${shellCmdsList}\n if test (count $tokens) -ge 2; and contains $tokens[2] $shell_cmds\n return 0\n end\n return 1\nend\ncomplete -c forgemap -f -n '__forgemap_needs_shell' -a '${shellValues}'\n\n# Slugs (depth 2) for commands that take one.\nfunction __forgemap_needs_slug\n set -l tokens (commandline -opc)\n set -l slug_cmds ${slugCmdsList}\n if test (count $tokens) -ge 2; and contains $tokens[2] $slug_cmds\n return 0\n end\n return 1\nend\n\ncomplete -c forgemap -f -n '__forgemap_needs_slug' \\\\\n -a '(forgemap list --format slug 2>/dev/null)'\n`;\n}\n\nexport const completionCommand = defineCommand({\n meta: {\n name: 'completion',\n description:\n 'Print a shell completion script. Source via `eval \"$(forgemap completion)\"`.'\n },\n args: {\n shell: {\n type: 'positional',\n description: `Shell flavor (${SUPPORTED.join(', ')}). Auto-detected from $SHELL if omitted.`,\n required: false\n },\n install: {\n type: 'boolean',\n description:\n \"Append the completion loader to your shell's rc file (idempotent) instead of printing\",\n default: false\n }\n },\n async run({ args }) {\n const requested = (args.shell ?? detectShell()) as Shell;\n if (!SUPPORTED.includes(requested)) {\n consola.error(\n `Unsupported shell \"${requested}\". Supported: ${SUPPORTED.join(', ')}.`\n );\n process.exitCode = 1;\n return;\n }\n\n if (args.install) {\n const loader =\n requested === 'fish'\n ? 'forgemap completion fish | source'\n : `eval \"$(forgemap completion ${requested})\"`;\n const { status, rcFile } = await installRcBlock(requested, 'completion', [\n loader\n ]);\n if (status === 'present') {\n consola.info(`forgemap completion already present in ${rcFile}.`);\n } else {\n const verb = status === 'updated' ? 'Updated' : 'Added';\n consola.success(`${verb} forgemap completion in ${rcFile}.`);\n consola.info(\n `Run \\`source ${rcFile}\\` or restart your shell to activate it.`\n );\n }\n return;\n }\n\n const specs = commandSpecs();\n const out =\n requested === 'fish'\n ? renderFish(specs)\n : requested === 'zsh'\n ? renderZsh(specs)\n : renderBash(specs);\n process.stdout.write(out);\n }\n});\n","import { defineCommand } from 'citty';\nimport { cdCommand } from './commands/cd.ts';\nimport { cleanupCommand } from './commands/cleanup.ts';\nimport { cloneCommand } from './commands/clone.ts';\nimport { completionCommand } from './commands/completion.ts';\nimport { configCommand } from './commands/config/index.ts';\nimport { deleteCommand } from './commands/delete.ts';\nimport { forgeCommand } from './commands/forge/index.ts';\nimport { importCommand } from './commands/import.ts';\nimport { infoCommand } from './commands/info.ts';\nimport { listCommand } from './commands/list.ts';\nimport { openCommand } from './commands/open.ts';\nimport { pathCommand } from './commands/path.ts';\nimport { pickCommand } from './commands/pick.ts';\nimport { shellInitCommand } from './commands/shell-init.ts';\nimport { statusCommand } from './commands/status.ts';\nimport { syncCommand } from './commands/sync.ts';\nimport { validateCommand } from './commands/validate.ts';\n\n// Injected at build time by vite's `define` (see vite.config.ts), sourced from\n// package.json's `version`. release-please bumps that field on release, so the\n// reported version tracks the published one instead of a hand-copied literal\n// that would silently drift.\ndeclare const __APP_VERSION__: string;\n\nexport const rootCommand = defineCommand({\n meta: {\n name: 'forgemap',\n version: __APP_VERSION__,\n description:\n 'Manage a local repo layout of the form <root>/<forge.dir>/<owner>/<repo>'\n },\n subCommands: {\n clone: cloneCommand,\n import: importCommand,\n cleanup: cleanupCommand,\n delete: deleteCommand,\n cd: cdCommand,\n path: pathCommand,\n open: openCommand,\n list: listCommand,\n pick: pickCommand,\n status: statusCommand,\n sync: syncCommand,\n validate: validateCommand,\n info: infoCommand,\n completion: completionCommand,\n 'shell-init': shellInitCommand,\n config: configCommand,\n forge: forgeCommand\n }\n});\n","import { runMain } from 'citty';\nimport { rootCommand } from '../cli.ts';\n\nrunMain(rootCommand);\n"],"mappings":"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"}
|