forgemap 0.1.0-dev.22-d31fc67 → 0.1.0-dev.23-9e4d2ae
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 +62 -46
- package/dist/bin/forgemap.mjs +808 -54
- package/dist/bin/forgemap.mjs.map +1 -1
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forgemap.mjs","sources":["../../src/commands/cd.ts","../../src/config/load.ts","../../src/utils/exec.ts","../../src/forges/github.ts","../../src/forges/registry.ts","../../src/slug/parse.ts","../../src/utils/path.ts","../../src/slug/resolve.ts","../../src/commands/clone.ts","../../src/commands/config/init.ts","../../src/commands/config/show.ts","../../src/commands/config/index.ts","../../src/commands/open.ts","../../src/commands/path.ts","../../src/repos/scan.ts","../../src/commands/pick.ts","../../src/commands/search.ts","../../src/commands/shell-init.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 { loadConfig } from 'c12';\nimport { dirname } from 'pathe';\nimport type { ForgeMapConfig, ForgeMapUserConfig } from './schema.ts';\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 explicit = options.configFile ?? envConfig;\n const cwd = explicit ? dirname(explicit) : (options.cwd ?? process.cwd());\n\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 defaults: DEFAULT_CONFIG\n });\n\n const merged: ForgeMapConfig = {\n root: config.root ?? DEFAULT_CONFIG.root,\n defaultForge: config.defaultForge ?? DEFAULT_CONFIG.defaultForge,\n forges: {\n ...DEFAULT_CONFIG.forges,\n ...config.forges\n }\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 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 { execInherit, hasCommand } from '../utils/exec.ts';\nimport type { CloneOptions, ForgeAdapter } from './types.ts';\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","import type { ForgeType } from '../config/schema.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 'gitlab':\n case 'gitea':\n case 'codeberg':\n throw new Error(\n `Forge type \"${type}\" is not implemented yet. Only \"github\" is supported in this release.`\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\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 { 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 { 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 { getForgeAdapter } from '../forges/registry.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 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 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 });\n\n consola.success(\n `Cloned ${resolved.owner}/${resolved.repo} → ${resolved.localPath}`\n );\n }\n});\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { dirname, join, resolve } from 'pathe';\n\nconst TEMPLATE = `/**\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 */\nexport default {\n root: '.',\n defaultForge: 'github',\n forges: {\n github: {\n type: 'github',\n host: 'github.com',\n dir: 'comGithub'\n }\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 outDir = resolve(process.cwd(), args.out);\n const target = join(outDir, 'forgemap.config.ts');\n\n await mkdir(dirname(target), { recursive: true });\n\n try {\n await writeFile(target, TEMPLATE, {\n encoding: 'utf8',\n flag: args.force ? 'w' : 'wx'\n });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'EEXIST') {\n consola.error(`${target} already exists. Use --force to overwrite.`);\n process.exitCode = 1;\n return;\n }\n throw error;\n }\n\n consola.success(`Wrote ${target}`);\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 { 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 { 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 { 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 const 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\n if (typeof choice === 'string' && choice) {\n process.stdout.write(`${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\nfunction renderTree(repos: ScannedRepo[]): string {\n const groups = new Map<string, ScannedRepo[]>();\n for (const r of repos) {\n const list = groups.get(r.forgeName);\n if (list) list.push(r);\n else groups.set(r.forgeName, [r]);\n }\n\n return formatTree(\n Array.from(groups, ([forge, items]) => ({\n text: colors.bold(forge),\n children: items.map((r) => ({\n text: `${colors.cyan(r.slug)} ${colors.dim(r.localPath)}`\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';\n\ntype Shell = 'zsh' | 'bash' | 'fish';\n\nconst SUPPORTED: Shell[] = ['zsh', 'bash', 'fish'];\n\nfunction 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\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 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 },\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 const out = requested === 'fish' ? renderFish(name) : renderPosix(name);\n process.stdout.write(out);\n }\n});\n","import { defineCommand } from 'citty';\nimport { cdCommand } from './commands/cd.ts';\nimport { cloneCommand } from './commands/clone.ts';\nimport { configCommand } from './commands/config/index.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';\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 cd: cdCommand,\n path: pathCommand,\n open: openCommand,\n search: searchCommand,\n pick: pickCommand,\n 'shell-init': shellInitCommand,\n config: configCommand\n }\n});\n","import { runMain } from 'citty';\nimport { rootCommand } from '../cli.ts';\n\nrunMain(rootCommand);\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"forgemap.mjs","sources":["../../src/commands/cd.ts","../../src/config/load.ts","../../src/utils/exec.ts","../../src/forges/git.ts","../../src/forges/github.ts","../../src/forges/registry.ts","../../src/utils/path.ts","../../src/repos/scan.ts","../../src/repos/cache.ts","../../src/slug/parse.ts","../../src/slug/resolve.ts","../../src/commands/clone.ts","../../src/commands/completion.ts","../../src/commands/config/init.ts","../../src/commands/config/show.ts","../../src/commands/config/index.ts","../../src/commands/open.ts","../../src/commands/path.ts","../../src/commands/pick.ts","../../src/commands/search.ts","../../src/commands/shell-init.ts","../../src/repos/git.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 { loadConfig } from 'c12';\nimport { dirname } from 'pathe';\nimport type { ForgeMapConfig, ForgeMapUserConfig } from './schema.ts';\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 explicit = options.configFile ?? envConfig;\n const cwd = explicit ? dirname(explicit) : (options.cwd ?? process.cwd());\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}\n\nexport interface CaptureOptions {\n cwd?: string;\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 stdio: ['ignore', 'pipe', 'pipe']\n });\n let stdout = '';\n let stderr = '';\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', rejectPromise);\n child.on('close', (code) => {\n resolvePromise({ code: code ?? 0, stdout, stderr });\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 { GitForgeConfig } from '../config/schema.ts';\nimport { execInherit, hasCommand } from '../utils/exec.ts';\nimport type { CloneOptions, ForgeAdapter } from './types.ts';\n\nfunction buildCloneUrl(opts: CloneOptions): 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\n// Exported for testing.\nexport const __test = { buildCloneUrl };\n","import { execInherit, hasCommand } from '../utils/exec.ts';\nimport type { CloneOptions, ForgeAdapter } from './types.ts';\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","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 { 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 { 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","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 { 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 { defineCommand } from 'citty';\nimport consola from 'consola';\n\ntype Shell = 'zsh' | 'bash' | 'fish';\nconst SUPPORTED: Shell[] = ['zsh', 'bash', 'fish'];\n\nconst SUBCOMMANDS = [\n 'clone',\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 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\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 },\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 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 { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { dirname, join, resolve } from 'pathe';\n\nconst TEMPLATE = `/**\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 */\nexport default {\n root: '.',\n defaultForge: 'github',\n forges: {\n github: {\n type: 'github',\n host: 'github.com',\n dir: 'comGithub'\n }\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 outDir = resolve(process.cwd(), args.out);\n const target = join(outDir, 'forgemap.config.ts');\n\n await mkdir(dirname(target), { recursive: true });\n\n try {\n await writeFile(target, TEMPLATE, {\n encoding: 'utf8',\n flag: args.force ? 'w' : 'wx'\n });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'EEXIST') {\n consola.error(`${target} already exists. Use --force to overwrite.`);\n process.exitCode = 1;\n return;\n }\n throw error;\n }\n\n consola.success(`Wrote ${target}`);\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 { 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 const 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\n if (typeof choice === 'string' && choice) {\n process.stdout.write(`${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\nfunction renderTree(repos: ScannedRepo[]): string {\n const groups = new Map<string, ScannedRepo[]>();\n for (const r of repos) {\n const list = groups.get(r.forgeName);\n if (list) list.push(r);\n else groups.set(r.forgeName, [r]);\n }\n\n return formatTree(\n Array.from(groups, ([forge, items]) => ({\n text: colors.bold(forge),\n children: items.map((r) => ({\n text: `${colors.cyan(r.slug)} ${colors.dim(r.localPath)}`\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';\n\ntype Shell = 'zsh' | 'bash' | 'fish';\n\nconst SUPPORTED: Shell[] = ['zsh', 'bash', 'fish'];\n\nfunction 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\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 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 },\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 const out = requested === 'fish' ? renderFish(name) : renderPosix(name);\n process.stdout.write(out);\n }\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 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\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 gitIn(localPath, ['fetch', '--all', '--prune']);\n}\n\nexport async function pullRepo(localPath: string): Promise<CaptureResult> {\n return gitIn(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","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.slug)} ${colors.red(`error: ${row.error ?? 'unknown'}`)}`;\n }\n const s = row.status;\n const parts: string[] = [colors.cyan(row.repo.slug)];\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\nfunction renderTree(rows: Row[]): string {\n const groups = new Map<string, Row[]>();\n for (const row of rows) {\n const list = groups.get(row.repo.forgeName);\n if (list) list.push(row);\n else groups.set(row.repo.forgeName, [row]);\n }\n return formatTree(\n Array.from(groups, ([forge, items]) => ({\n text: colors.bold(forge),\n children: items.map((row) => ({ text: statusLine(row) }))\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 outcomes.push({\n repo,\n status: 'failed',\n message: (result.stderr || result.stdout).trim().split('\\n')[0]\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 { cloneCommand } from './commands/clone.ts';\nimport { completionCommand } from './commands/completion.ts';\nimport { configCommand } from './commands/config/index.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 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":["fingerprint","SUPPORTED","detectShell","renderFish","renderTree"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://www.schemastore.org/package.json",
|
|
3
3
|
"name": "forgemap",
|
|
4
|
-
"version": "0.1.0-dev.
|
|
4
|
+
"version": "0.1.0-dev.23-9e4d2ae",
|
|
5
5
|
"description": "CLI that manages a local repo layout grouped by git server, organization and repository name.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"cli",
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
"test": "vitest run",
|
|
82
82
|
"test:watch": "vitest",
|
|
83
83
|
"test:coverage": "vitest run --coverage",
|
|
84
|
+
"bench": "node --experimental-strip-types bench/scan.ts",
|
|
84
85
|
"check": "pnpm lint && pnpm format",
|
|
85
86
|
"check:fix": "pnpm lint:fix && pnpm format:fix",
|
|
86
87
|
"taze": "taze",
|