// SPDX-License-Identifier: MIT // Copyright (c) 2026 sol pbc import { existsSync } from 'node:fs'; import { resolve } from 'node:path'; import { execFileSync } from 'node:child_process'; import { parseGitUrl, toBeacon, beaconToHttps } from '../lib/beacon.js'; import { requireNotAgent } from '../lib/agent.js'; import { which } from '../lib/compat.js'; import { mark, name } from '../lib/brand.js'; export default function register(program) { program .command('adopt') .argument('', 'Beacon URI, git URL, or slug to adopt (e.g. vit:github.com/org/repo)') .argument('[name]', 'Local directory name (defaults to repo name)') .description('Fork or clone a project') .option('-v, --verbose', 'Show step-by-step details') .action(async (beacon, targetName, opts) => { try { const gate = requireNotAgent(); if (!gate.ok) { console.error(`${name} adopt must be run by a human. run it in your own terminal.`); process.exitCode = 1; return; } const { verbose } = opts; // resolve beacon if (verbose) console.log(`[verbose] resolving beacon: ${beacon}`); const httpsUrl = beaconToHttps(beacon); const parsed = parseGitUrl(httpsUrl); const beaconUri = 'vit:' + toBeacon(httpsUrl); if (verbose) console.log(`[verbose] beacon: ${beaconUri}`); if (verbose) console.log(`[verbose] https: ${httpsUrl}`); // determine directory name const dirName = targetName || parsed.repo; const dirPath = resolve(dirName); if (verbose) console.log(`[verbose] target directory: ${dirPath}`); // fail fast if directory exists if (existsSync(dirPath)) { console.error(`Directory already exists: ${dirName}`); process.exitCode = 1; return; } // detect gh + github host const ghPath = which('gh'); const isGitHub = parsed.host === 'github.com'; if (verbose) console.log(`[verbose] gh available: ${ghPath ? 'yes' : 'no'}, github host: ${isGitHub ? 'yes' : 'no'}`); if (ghPath && isGitHub) { if (verbose) console.log(`[verbose] gh found at ${ghPath}, forking via gh`); try { execFileSync('gh', ['repo', 'fork', httpsUrl, '--clone', '--', dirName], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], }); } catch (err) { console.error(`Fork failed: ${(err.stderr || err.message || '').trim()}`); process.exitCode = 1; return; } } else { if (verbose) console.log(`[verbose] cloning via git`); try { execFileSync('git', ['clone', httpsUrl, dirName], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], }); } catch (err) { console.error(`Clone failed: ${(err.stderr || err.message || '').trim()}`); process.exitCode = 1; return; } } // success output console.log(`${mark} beacon: ${beaconUri}`); console.log(`${mark} directory: ${dirName}`); console.log(`run: cd ${dirName}`); console.log(''); console.log(`next: start your agent and ask it to run '${name} init'`); } catch (err) { console.error(err instanceof Error ? err.message : String(err)); process.exitCode = 1; } }); }