UNPKG

@kya-os/cli

Version:

CLI for MCP-I setup and management

107 lines 4.52 kB
import chalk from "chalk"; import { Command } from "commander"; import { renderSetupResult } from "../utils/dco/render.js"; import { runDcoSetup } from "../utils/dco/setup.js"; import { collectDcoStatus } from "../utils/dco/status.js"; export async function dcoSetup(options = {}) { if (!options.json) { console.log(chalk.cyan("\nSetting up DCO sign-off, commit signing, and PR attribution\n")); } const setupOptions = { global: options.global, dryRun: options.dryRun, skipGithub: options.skipGithub, skipClaude: options.skipClaude, force: options.force, interactive: options.json || options.yes ? false : undefined, }; let result; try { result = await runDcoSetup(setupOptions); } catch (error) { // Belt and braces: runDcoSetup reports failures as step results, but no // escaping rejection may take down the process without a message. const message = error instanceof Error ? error.message : String(error); if (options.json) { console.log(JSON.stringify({ success: false, error: message }, null, 2)); } else { console.error(chalk.red(`\nSetup failed unexpectedly: ${message}\n`)); } // v8 ignore: process.exit is unreachable under vitest by design (the // repo-mandated test-environment guard) and must stay that way. /* v8 ignore start */ if (process.env.NODE_ENV !== "test" && !process.env.VITEST) { process.exit(1); } /* v8 ignore stop */ return; } if (options.json) { console.log(JSON.stringify({ success: result.ok, actionRequired: result.actionRequired, steps: result.steps, agent: result.agent, human: result.human, privateKeyPath: result.privateKeyPath, fingerprint: result.fingerprint, // Surfaced to automation too: without it a caller only sees a // successful identities step and may assume no later re-prompt. metadataPersistWarning: result.metadataPersistWarning, }, null, 2)); } else { renderSetupResult(result); } // v8 ignore: same test-environment guard as above. /* v8 ignore start */ if (process.env.NODE_ENV !== "test" && !process.env.VITEST) { process.exit(result.ok ? (result.actionRequired ? 2 : 0) : 1); } /* v8 ignore stop */ } export async function dcoStatus(options = {}) { const result = await collectDcoStatus(process.cwd()); if (options.json) { console.log(JSON.stringify(result, null, 2)); return; } console.log(chalk.cyan("\nDCO / attribution status\n")); const width = Math.max(...result.checks.map((c) => c.label.length)); for (const check of result.checks) { const state = check.state === "ok" ? chalk.green("ok") : check.state === "warn" ? chalk.yellow("warn") : chalk.red("missing"); console.log(` ${check.label.padEnd(width)} ${state}`); if (check.detail) { console.log(` ${" ".repeat(width)} ${chalk.gray(check.detail)}`); } } console.log(""); } export function createDcoCommand() { const dco = new Command("dco").description("Set up DCO sign-off, commit signing, and PR attribution for your agent"); dco .command("setup") .description("Sign commits with your agent's identity key and attribute PRs to your agent. " + "Exit codes: 0 = complete, 1 = a step failed, 2 = complete but user action pending.") .option("--global", "Write git config globally instead of repo-local") .option("--dry-run", "Show what would change without writing anything") .option("--json", "Output in JSON format for automation") .option("--skip-github", "Skip uploading the signing key to GitHub") .option("--skip-claude", "Skip Claude Code attribution configuration") .option("--force", "Overwrite conflicting existing signing configuration") .option("-y, --yes", "Run non-interactively, never prompt") .action((options) => dcoSetup(options)); dco .command("status") .description("Show the current DCO/attribution setup state") .option("--json", "Output in JSON format for automation") .action((options) => dcoStatus(options)); return dco; } //# sourceMappingURL=dco.js.map