@blockxai/camp-codegen
Version: 
JavaScript/TypeScript SDK for Camp Codegen AI → Compile → Deploy API (parity with Python SDK)
200 lines (199 loc) • 8.16 kB
JavaScript
/* eslint-disable no-console */
// Simple CLI matching Python SDK capabilities (non-interactive)
// Commands:
// - pipeline:start --prompt "..." [--network str] [--maxIters N] [--filename str] [--arg val]*
// - job:status <jobId>
// - job:logs <jobId> [--since N]
// - job:wait <jobId> [--timeout 900] [--interval 2] [--stream]
// - artifacts <jobId> [--include all|sources|abis|scripts]
// - erc20:deploy --name --symbol --supply N [--network str] [--owner addr]
// - ai:generate --prompt "..."
// - ai:fix --code "..." --errors "..."
// - ai:compile --filename "..." --code "..."
import { AcadClient } from "./index.js";
function getArgv() {
    return (globalThis?.process?.argv ?? []);
}
function print(obj) {
    try {
        console.log(JSON.stringify(obj, null, 2));
    }
    catch {
        console.log(String(obj));
    }
}
function getFlag(name, fallback) {
    const argv = getArgv();
    const i = argv.indexOf(`--${name}`);
    if (i !== -1 && i + 1 < argv.length)
        return argv[i + 1];
    const eq = argv.find((a) => a.startsWith(`--${name}=`));
    if (eq)
        return eq.slice(name.length + 3);
    return fallback;
}
function getBool(name, fallback = false) {
    const argv = getArgv();
    if (argv.includes(`--${name}`))
        return true;
    const eq = argv.find((a) => a.startsWith(`--${name}=`));
    if (eq) {
        const v = eq.split("=")[1];
        return v === "1" || v === "true";
    }
    return fallback;
}
function getAllFlags(name) {
    const argv = getArgv();
    const out = [];
    for (let i = 0; i < argv.length; i++) {
        if (argv[i] === `--${name}` && i + 1 < argv.length)
            out.push(argv[i + 1]);
        if (argv[i].startsWith(`--${name}=`))
            out.push(argv[i].split("=")[1]);
    }
    return out;
}
export async function run() {
    const argv = getArgv().slice(2);
    const cmd = argv[0];
    const client = new AcadClient();
    try {
        switch (cmd) {
            case "pipeline:start": {
                const prompt = getFlag("prompt");
                if (!prompt)
                    throw new Error("--prompt is required");
                const network = getFlag("network");
                const maxItersStr = getFlag("maxIters");
                const filename = getFlag("filename");
                const args = getAllFlags("arg");
                const constructorArgs = args.map((a) => {
                    try {
                        return JSON.parse(a);
                    }
                    catch {
                        return a;
                    }
                });
                const maxIters = maxItersStr ? parseInt(maxItersStr, 10) : undefined;
                let jobId;
                if (network) {
                    jobId = await client.start_pipeline(prompt, network, maxIters, filename, constructorArgs.length ? constructorArgs : undefined);
                }
                else {
                    jobId = await client.start_pipeline_auto(prompt, { maxIters, filename, constructorArgs: constructorArgs.length ? constructorArgs : undefined });
                }
                print({ jobId });
                break;
            }
            case "job:status": {
                const jobId = argv[1];
                if (!jobId)
                    throw new Error("usage: job:status <jobId>");
                const job = await client.get_job_status(jobId);
                print(job);
                break;
            }
            case "job:logs": {
                const jobId = argv[1];
                if (!jobId)
                    throw new Error("usage: job:logs <jobId> [--since N]");
                const sinceStr = getFlag("since", "0");
                const since = parseInt(sinceStr || "0", 10) || 0;
                const res = await client.get_job_logs(jobId, since);
                print(res);
                break;
            }
            case "job:wait": {
                const jobId = argv[1];
                if (!jobId)
                    throw new Error("usage: job:wait <jobId> [--timeout 900] [--interval 2] [--stream]");
                const timeoutStr = getFlag("timeout", "900");
                const intervalStr = getFlag("interval", "2");
                const stream = getBool("stream", false);
                const job = await client.wait_for_completion(jobId, {
                    timeoutSec: parseInt(timeoutStr || "900", 10) || 900,
                    intervalSec: parseInt(intervalStr || "2", 10) || 2,
                    streamLogs: stream,
                    onUpdate: stream ? (j) => console.error(`[${j.state}] ${j.id}`) : undefined,
                });
                print(job);
                if (job.state !== "completed") {
                    const summary = client.summarize_failure(job);
                    if (summary)
                        console.error(summary);
                }
                break;
            }
            case "artifacts": {
                const jobId = argv[1];
                if (!jobId)
                    throw new Error("usage: artifacts <jobId> [--include all|sources|abis|scripts]");
                const include = getFlag("include", "all");
                const a = await client.get_artifacts(jobId, include);
                print(a);
                break;
            }
            case "erc20:deploy": {
                const name = getFlag("name");
                const symbol = getFlag("symbol");
                const supplyStr = getFlag("supply");
                if (!name || !symbol || !supplyStr)
                    throw new Error("--name, --symbol, --supply are required");
                const network = getFlag("network");
                const owner = getFlag("owner");
                const supply = String(parseInt(supplyStr, 10));
                const res = await client.deploy_erc20(name, symbol, supply, network || null, owner || undefined);
                print(res);
                break;
            }
            case "ai:generate": {
                const prompt = getFlag("prompt");
                if (!prompt)
                    throw new Error("--prompt is required");
                const res = await client.ai_generate(prompt);
                print(res);
                break;
            }
            case "ai:fix": {
                const code = getFlag("code");
                const errors = getFlag("errors");
                if (!code || !errors)
                    throw new Error("--code and --errors are required");
                const res = await client.ai_fix(code, errors);
                print(res);
                break;
            }
            case "ai:compile": {
                const filename = getFlag("filename");
                const code = getFlag("code");
                if (!filename || !code)
                    throw new Error("--filename and --code are required");
                const res = await client.ai_compile(filename, code);
                print(res);
                break;
            }
            case "help":
            default: {
                console.log(`Camp Codegen CLI\n\n` +
                    `Usage:\n` +
                    `  camp pipeline:start --prompt "..." [--network basecamp] [--maxIters 5] [--filename AIGenerated.sol] [--arg value]*\n` +
                    `  camp job:status <jobId>\n` +
                    `  camp job:logs <jobId> [--since 0]\n` +
                    `  camp job:wait <jobId> [--timeout 900] [--interval 2] [--stream]\n` +
                    `  camp artifacts <jobId> [--include all|sources|abis|scripts]\n` +
                    `  camp erc20:deploy --name NAME --symbol SYM --supply 1000000 [--network basecamp] [--owner 0x...]\n` +
                    `  camp ai:generate --prompt "..."\n` +
                    `  camp ai:fix --code "..." --errors "..."\n` +
                    `  camp ai:compile --filename Foo.sol --code "..."\n`);
                break;
            }
        }
    }
    catch (err) {
        console.error(err?.message || String(err));
        (globalThis?.process?.exit?.(1));
    }
}
// no self-run; bin/cli.mjs will call run()