forgemap 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -47
- package/dist/bin/forgemap.mjs +3113 -2556
- package/dist/bin/forgemap.mjs.map +1 -1
- package/dist/config/define.mjs +6 -5
- package/dist/config/define.mjs.map +1 -1
- package/dist/index.mjs +1 -4
- package/package.json +9 -9
- package/dist/index.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forgemap.mjs","sources":["../../src/commands/cd.ts","../../src/utils/path.ts","../../src/config/load.ts","../../src/utils/exec.ts","../../src/forges/git.ts","../../src/utils/concurrency.ts","../../src/forges/github.ts","../../src/forges/registry.ts","../../src/repos/scan.ts","../../src/repos/cache.ts","../../src/repos/git.ts","../../src/slug/parse.ts","../../src/commands/cleanup.ts","../../src/slug/resolve.ts","../../src/commands/clone.ts","../../src/utils/shell.ts","../../src/commands/completion.ts","../../src/config/write.ts","../../src/commands/config/init.ts","../../src/commands/config/show.ts","../../src/commands/config/index.ts","../../src/repos/import.ts","../../src/commands/import.ts","../../src/commands/open.ts","../../src/commands/path.ts","../../src/commands/pick.ts","../../src/commands/search.ts","../../src/commands/shell-init.ts","../../src/commands/status.ts","../../src/commands/sync.ts","../../src/commands/validate.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 LoadedConfig {\n config: ForgeMapConfig;\n configFile: string | undefined;\n cwd: string;\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 const explicit =\n options.configFile ??\n envConfig ??\n findConfigUp(startDir) ??\n findGlobalConfig();\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 return {\n config: merged,\n configFile: configFile || undefined,\n cwd\n };\n}\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","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 { 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 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 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 // 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","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\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 { readdir, rm, rmdir } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { colors } from 'consola/utils';\nimport { dirname, join } from 'pathe';\nimport { resolveRoot } from '../utils/path.ts';\nimport { loadForgeMapConfig } from '../config/load.ts';\nimport type { ForgeMapConfig, ForgeType } from '../config/schema.ts';\nimport { getForgeAdapter } from '../forges/registry.ts';\nimport type { RemoteCheckInput, RemoteCheckResult } from '../forges/types.ts';\nimport { removeCachedRepo, scanReposCached } from '../repos/cache.ts';\nimport {\n getLastCommitUnix,\n getOriginUrl,\n getRepoStatus,\n hasUnpushedCommits,\n isGitRepo\n} from '../repos/git.ts';\nimport type { ScannedRepo } from '../repos/scan.ts';\nimport { parseSlug } from '../slug/parse.ts';\nimport { mapLimit } from '../utils/concurrency.ts';\n\nconst DAY_SECONDS = 86_400;\nconst LOCAL_CONCURRENCY = 16;\nconst REMOTE_CONCURRENCY = 10;\n\n/**\n * A stale repo that has an origin. `dirty` / `unpushed` record its local\n * state; the run logic decides whether those block deletion (overridable via\n * flags) while a missing remote is always a hard stop. Carries the origin\n * identity used for the remote-existence check.\n */\ninterface Candidate {\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 lastCommitUnix: number;\n dirty: boolean;\n unpushed: boolean;\n}\n\n/**\n * Local gates (no network). Returns null for repos we ignore entirely:\n * non-git dirs, repos without an origin, and repos that are NOT stale (their\n * newest local commit is within the cutoff). A stale repo with an origin is\n * always returned with its dirty/unpushed state recorded.\n */\nasync function evaluate(\n repo: ScannedRepo,\n cutoffUnix: number\n): Promise<Candidate | 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 (lastCommitUnix === null || lastCommitUnix > cutoffUnix) return null;\n\n const status = await getRepoStatus(repo.localPath);\n const dirty = status.dirty;\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 { repo, origin, owner, name, lastCommitUnix, dirty, unpushed };\n}\n\n/** Check each candidate's remote, grouped by forge so GitHub can batch. */\nasync function classifyRemotes(\n candidates: Candidate[]\n): Promise<Map<string, RemoteCheckResult>> {\n const byType = new Map<ForgeType, Candidate[]>();\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\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 'no-cache': {\n type: 'boolean',\n description: 'Skip the scanned-repos cache',\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 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['no-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 evaluate(repo, cutoffUnix)\n )\n ).filter((c): c is Candidate => c !== null);\n\n const includeDirty = Boolean(args['include-dirty']);\n const includeUnpushed = Boolean(args['include-unpushed']);\n\n // Dirty / unpushed only block when the matching --include flag is off.\n // A missing remote is ALWAYS a hard stop (never overridable). So only the\n // locally-eligible repos need a remote check.\n const localOk = (c: Candidate) =>\n (!c.dirty || includeDirty) && (!c.unpushed || includeUnpushed);\n const remoteStates = await classifyRemotes(stale.filter(localOk));\n\n const candidates: Candidate[] = [];\n const kept: Array<{ repo: Candidate; reason: string }> = [];\n for (const c of stale) {\n if (c.dirty && !includeDirty) {\n kept.push({ repo: c, reason: 'uncommitted changes' });\n } else if (c.unpushed && !includeUnpushed) {\n kept.push({ repo: c, reason: 'unpushed commits' });\n } else {\n const state = remoteStates.get(c.repo.localPath)?.state;\n if (state === 'exists' || state === 'moved') candidates.push(c);\n else {\n kept.push({\n repo: c,\n reason:\n state === 'gone'\n ? 'remote no longer exists'\n : 'remote unreachable'\n });\n }\n }\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 ]\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((c) => c.dirty || c.unpushed).length;\n if (losing > 0) {\n consola.warn(\n `${losing} of these have uncommitted/unpushed 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\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. */\nasync 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). */\nasync 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 { 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 `search`/`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 { 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\nconst SUBCOMMANDS = [\n 'clone',\n 'import',\n 'cleanup',\n 'cd',\n 'path',\n 'open',\n 'search',\n 'pick',\n 'status',\n 'sync',\n 'validate',\n 'shell-init',\n 'completion',\n 'config'\n];\n\nconst SLUG_COMMANDS = ['clone', 'cd', 'path', 'open', 'search', 'pick'];\n\nfunction renderBash(): string {\n return `# forgemap bash completion — drop into your ~/.bashrc:\n# eval \"$(forgemap completion bash)\"\n_forgemap_completion() {\n local cur prev cmd words\n COMPREPLY=()\n cur=\"\\${COMP_WORDS[COMP_CWORD]}\"\n cmd=\"\\${COMP_WORDS[1]}\"\n\n if [ \"$COMP_CWORD\" = \"1\" ]; then\n COMPREPLY=( $(compgen -W \"${SUBCOMMANDS.join(' ')}\" -- \"$cur\") )\n return\n fi\n\n case \"$cmd\" in\n ${SLUG_COMMANDS.join('|')})\n local slugs\n slugs=$(forgemap search '' --format slug 2>/dev/null)\n COMPREPLY=( $(compgen -W \"$slugs\" -- \"$cur\") )\n ;;\n esac\n}\ncomplete -F _forgemap_completion forgemap\n`;\n}\n\nfunction renderZsh(): string {\n return `# forgemap zsh completion — drop into your ~/.zshrc:\n# eval \"$(forgemap completion zsh)\"\n_forgemap() {\n local context state line\n local -a subcommands slug_cmds\n subcommands=(${SUBCOMMANDS.map((s) => `'${s}'`).join(' ')})\n slug_cmds=(${SLUG_COMMANDS.map((s) => `'${s}'`).join(' ')})\n\n _arguments -C \\\\\n '1: :->cmd' \\\\\n '*::arg:->args'\n\n case \"$state\" in\n cmd) _describe 'forgemap subcommand' subcommands ;;\n args)\n if (( $slug_cmds[(I)$words[1]] )); then\n local -a slugs\n slugs=(\"\\${(@f)$(forgemap search '' --format slug 2>/dev/null)}\")\n _describe 'slug' slugs\n fi\n ;;\n esac\n}\ncompdef _forgemap forgemap\n`;\n}\n\nfunction renderFish(): string {\n const slugCmdsList = SLUG_COMMANDS.map((s) => `\"${s}\"`).join(' ');\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 '${SUBCOMMANDS.join(' ')}'\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 search \"\" --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 out =\n requested === 'fish'\n ? renderFish()\n : requested === 'zsh'\n ? renderZsh()\n : renderBash();\n process.stdout.write(out);\n }\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 { 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/search hits the hot path.\n await scanReposCached({\n config: result.derived,\n configDir: path,\n useCache: false\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 { parseSlug } from '../slug/parse.ts';\nimport { resolveSlug } from '../slug/resolve.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: 'owner/repo, forge:owner/repo, or full URL',\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 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 const { cmd, args: cmdArgs } = platformOpen(resolved.localPath);\n consola.info(`Opening ${resolved.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 { loadForgeMapConfig } from '../config/load.ts';\nimport { dirname } from 'pathe';\nimport { parseSlug } from '../slug/parse.ts';\nimport { resolveSlug } from '../slug/resolve.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: 'owner/repo, forge:owner/repo, or full URL',\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 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 process.stdout.write(`${resolved.localPath}\\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 { 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 let candidates: ScannedRepo[];\n if (args.query) {\n const fuse = new Fuse(all, {\n keys: ['slug', 'owner', 'repo'],\n threshold: 0.3,\n ignoreLocation: true\n });\n candidates = fuse.search(args.query).map((r) => r.item);\n } else {\n candidates = all;\n }\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 (!process.stdin.isTTY) {\n consola.error(\n 'pick requires an interactive terminal. Use `forgemap search` for non-interactive output.'\n );\n process.exitCode = 1;\n return;\n }\n\n // `$(forgemap pick)` captures stdout, so the interactive TUI must not go\n // there. consola/clack writes the UI to stdout AND reads stdout.rows/columns\n // for layout — but a captured stdout is a pipe (no rows → nothing renders).\n // So for the duration of the prompt: route stdout writes to stderr (the real\n // TTY) and borrow stderr's dimensions, then restore. stdout stays clean for\n // the chosen path only.\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 if (typeof choice === 'string' && choice) {\n realWrite.call(out, `${choice}\\n`);\n }\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 { 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 searchCommand = defineCommand({\n meta: {\n name: 'search',\n description:\n 'Fuzzy-search cloned repos by owner/repo and print matching repos'\n },\n args: {\n query: {\n type: 'positional',\n description: 'Search term (matched fuzzily against <owner>/<repo>)',\n required: true\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 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 }) {\n const loaded = await loadForgeMapConfig({ configFile: args.config });\n const configDir = loaded.configFile\n ? dirname(loaded.configFile)\n : loaded.cwd;\n const repos = await scanRepos({ config: loaded.config, configDir });\n\n const fuse = new Fuse(repos, {\n keys: ['slug', 'owner', 'repo'],\n threshold: 0.3,\n ignoreLocation: true,\n includeScore: true\n });\n\n const limit = args.limit ? Number.parseInt(args.limit, 10) : undefined;\n const results = fuse.search(args.query, limit ? { limit } : undefined);\n const items = results.map((r) => r.item);\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') consola.info(`No matches for \"${args.query}\".`);\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 { 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 search \"$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 search $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 { 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 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 query: {\n type: 'string',\n description: 'Fuzzy filter against <owner>/<repo>'\n },\n 'no-cache': {\n type: 'boolean',\n description: 'Skip the scanned-repos cache',\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 (!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['no-cache']\n });\n\n if (args.forge) {\n repos = repos.filter((r) => r.forgeName === args.forge);\n }\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 { 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 query: {\n type: 'string',\n description: 'Fuzzy filter against <owner>/<repo>'\n },\n 'no-cache': {\n type: 'boolean',\n description: 'Skip the scanned-repos cache',\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 let repos = await scanReposCached({\n config: loaded.config,\n configDir,\n useCache: !args['no-cache']\n });\n\n if (args.forge) {\n repos = repos.filter((r) => r.forgeName === args.forge);\n }\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 { 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 { importCommand } from './commands/import.ts';\nimport { openCommand } from './commands/open.ts';\nimport { pathCommand } from './commands/path.ts';\nimport { pickCommand } from './commands/pick.ts';\nimport { searchCommand } from './commands/search.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\nexport const rootCommand = defineCommand({\n meta: {\n name: 'forgemap',\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 cd: cdCommand,\n path: pathCommand,\n open: openCommand,\n search: searchCommand,\n pick: pickCommand,\n status: statusCommand,\n sync: syncCommand,\n validate: validateCommand,\n completion: completionCommand,\n 'shell-init': shellInitCommand,\n config: configCommand\n }\n});\n","import { runMain } from 'citty';\nimport { rootCommand } from '../cli.ts';\n\nrunMain(rootCommand);\n"],"names":["DEFAULT_CONFIG","listDirs","fingerprint","LOCAL_CONCURRENCY","REMOTE_CONCURRENCY","renderFish","SUPPORTED","ALLOWED_FORMATS","severitySymbol","renderTree"],"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/commands/completion.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/repos/import.ts","../../src/commands/import.ts","../../src/commands/info.ts","../../src/repos/match.ts","../../src/repos/picker.ts","../../src/slug/locate.ts","../../src/commands/open.ts","../../src/commands/path.ts","../../src/commands/pick.ts","../../src/repos/filter.ts","../../src/commands/search.ts","../../src/commands/shell-init.ts","../../src/commands/status.ts","../../src/commands/sync.ts","../../src/commands/validate.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\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 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 `search`/`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 { 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\nconst SUBCOMMANDS = [\n 'clone',\n 'import',\n 'cleanup',\n 'delete',\n 'cd',\n 'path',\n 'open',\n 'search',\n 'pick',\n 'status',\n 'sync',\n 'validate',\n 'shell-init',\n 'completion',\n 'config'\n];\n\nconst SLUG_COMMANDS = [\n 'clone',\n 'cd',\n 'path',\n 'open',\n 'search',\n 'pick',\n 'delete'\n];\n\nfunction renderBash(): string {\n return `# forgemap bash completion — drop into your ~/.bashrc:\n# eval \"$(forgemap completion bash)\"\n_forgemap_completion() {\n local cur prev cmd words\n COMPREPLY=()\n cur=\"\\${COMP_WORDS[COMP_CWORD]}\"\n cmd=\"\\${COMP_WORDS[1]}\"\n\n if [ \"$COMP_CWORD\" = \"1\" ]; then\n COMPREPLY=( $(compgen -W \"${SUBCOMMANDS.join(' ')}\" -- \"$cur\") )\n return\n fi\n\n case \"$cmd\" in\n ${SLUG_COMMANDS.join('|')})\n local slugs\n slugs=$(forgemap search '' --format slug 2>/dev/null)\n COMPREPLY=( $(compgen -W \"$slugs\" -- \"$cur\") )\n ;;\n esac\n}\ncomplete -F _forgemap_completion forgemap\n`;\n}\n\nfunction renderZsh(): string {\n return `# forgemap zsh completion — drop into your ~/.zshrc:\n# eval \"$(forgemap completion zsh)\"\n_forgemap() {\n local context state line\n local -a subcommands slug_cmds\n subcommands=(${SUBCOMMANDS.map((s) => `'${s}'`).join(' ')})\n slug_cmds=(${SLUG_COMMANDS.map((s) => `'${s}'`).join(' ')})\n\n _arguments -C \\\\\n '1: :->cmd' \\\\\n '*::arg:->args'\n\n case \"$state\" in\n cmd) _describe 'forgemap subcommand' subcommands ;;\n args)\n if (( $slug_cmds[(I)$words[1]] )); then\n local -a slugs\n slugs=(\"\\${(@f)$(forgemap search '' --format slug 2>/dev/null)}\")\n _describe 'slug' slugs\n fi\n ;;\n esac\n}\ncompdef _forgemap forgemap\n`;\n}\n\nfunction renderFish(): string {\n const slugCmdsList = SLUG_COMMANDS.map((s) => `\"${s}\"`).join(' ');\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 '${SUBCOMMANDS.join(' ')}'\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 search \"\" --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 out =\n requested === 'fish'\n ? renderFish()\n : requested === 'zsh'\n ? renderZsh()\n : renderBash();\n process.stdout.write(out);\n }\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 { 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/search 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 Fuse, { type IFuseOptions } from 'fuse.js';\nimport type { ScannedRepo } from './scan.ts';\n\n/**\n * The one Fuse configuration every fuzzy lookup shares — `search`, `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 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 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 search` 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 type { ScannedRepo } from './scan.ts';\n\nconst FLAG = '--filter';\n\n/**\n * Shared `--filter` option for the commands that enumerate repos\n * (`status`, `sync`, `search`), 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 { 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 searchCommand = defineCommand({\n meta: {\n name: 'search',\n description:\n 'Fuzzy-search cloned repos by owner/repo and print matching repos'\n },\n args: {\n query: {\n type: 'positional',\n description: 'Search term (matched fuzzily against <owner>/<repo>)',\n required: true\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 searching, 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 const items = matchRepos(repos, args.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') consola.info(`No matches for \"${args.query}\".`);\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 { 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 search \"$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 search $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 { 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 { importCommand } from './commands/import.ts';\nimport { infoCommand } from './commands/info.ts';\nimport { openCommand } from './commands/open.ts';\nimport { pathCommand } from './commands/path.ts';\nimport { pickCommand } from './commands/pick.ts';\nimport { searchCommand } from './commands/search.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 search: searchCommand,\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 }\n});\n","import { runMain } from 'citty';\nimport { rootCommand } from '../cli.ts';\n\nrunMain(rootCommand);\n"],"mappings":"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"}
|