Loading...
Loading...
Turn any CLI tool into a fully typed JavaScript/TypeScript API using cli-to-js
npx skill4agent add aradotso/trending-skills cli-to-js-api-wrapperSkill by ara.so — Daily 2026 Skills collection.
cli-to-js--helpnpm install cli-to-jsconvertCliToJs(binary)--helpfromHelpText(binary, text)api.subcommand({ flag: value })_api.command({ _: ["file.txt"] }){ dryRun: true }--dry-run| JS option | CLI output |
|---|---|
| |
| (omitted) |
| |
| |
| |
| |
| |
import { convertCliToJs } from "cli-to-js";
// Wrap any installed binary
const git = await convertCliToJs("git");
const npm = await convertCliToJs("npm");
// Call subcommands as methods
const result = await git.status();
console.log(result.stdout);
console.log(result.exitCode);
// Pass flags as options
await git.commit({ message: "fix: update logic", all: true });
// → git commit --message "fix: update logic" --all
// Positional arguments via _
const { stdout } = await git.diff({ nameOnly: true, _: ["HEAD~1"] });
const changedFiles = stdout.trim().split("\n");import { convertCliToJs } from "cli-to-js";
const git = await convertCliToJs<{
commit: { message?: string; all?: boolean; amend?: boolean };
push: { force?: boolean; setUpstream?: string };
diff: { nameOnly?: boolean; stat?: boolean; _?: string[] };
}>("git");
// Fully autocompleted and type-checked
await git.commit({ message: "hello", all: true });
await git.push({ force: true });
// Type error — foobar doesn't exist
await git.push({ foobar: true }); // ❌ compile errorconst git = await convertCliToJs("git");
// .text() — trimmed stdout string
const branch = await git.branch({ showCurrent: true }).text();
// "main"
// .lines() — stdout split into array
const files = await git.diff({ nameOnly: true, _: ["HEAD~1"] }).lines();
// ["src/index.ts", "src/utils.ts"]
// .json<T>() — parse stdout as JSON
const packages = await npm.outdated({ json: true }).json<Record<string, { current: string }>>();
// { "lodash": { current: "4.17.20" }, ... }
// Raw result
const result = await git.log({ oneline: true, n: "5" });
result.stdout; // string
result.stderr; // string
result.exitCode; // numberconst git = await convertCliToJs("git", { subcommands: true });
const errors = git.$validate("commit", { massage: "fix typo" });
// [{ kind: "unknown-flag", name: "massage", suggestion: "message",
// message: 'Unknown flag "massage". Did you mean "message"?' }]
// Always validate before running in agent workflows
if (errors.length === 0) {
await git.commit({ message: "fix typo" });
} else {
// Use errors[0].suggestion to self-correct
console.log("Suggestion:", errors[0].suggestion);
}
// Validate root command options
const rootErrors = git.$validate({ unknownFlag: true });// Eager: parse all subcommands up front
const git = await convertCliToJs("git", { subcommands: true });
const commitFlags = git.$schema.command.subcommands
.find((s) => s.name === "commit")?.flags;
// Lazy: parse one subcommand on demand
const git2 = await convertCliToJs("git");
const commitSchema = await git2.$parse("commit");
console.log(commitSchema.flags);
// Parse all subcommands lazily
await git2.$parse();const api = await convertCliToJs("my-tool");
// Callbacks: real-time output + buffered result
const result = await api.build(
{ watch: false },
{
onStdout: (data) => process.stdout.write(data),
onStderr: (data) => process.stderr.write(data),
}
);
// Async iterator via $spawn
const proc = api.$spawn.test({ _: ["--watch"] });
for await (const line of proc) {
console.log(line);
if (line.includes("failed")) proc.kill();
}
console.log("Exit code:", await proc.exitCode);
// Direct spawnCommand
import { spawnCommand } from "cli-to-js";
const dev = spawnCommand("npm", ["run", "dev"]);
for await (const line of dev) {
if (line.includes("ready")) {
console.log("Server started");
break;
}
}const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
await api.build(
{ minify: true },
{
cwd: "/my/project",
env: { ...process.env, NODE_ENV: "production" },
timeout: 60_000,
signal: controller.signal,
stdio: "inherit", // pass through to terminal for interactive CLIs
}
);const git = await convertCliToJs("git");
// Get the shell string instead of running it
git.$command.commit({ message: "deploy", all: true });
// "git commit --message deploy --all"
// Compose into a script
import { script } from "cli-to-js";
const deploy = script(
git.$command.commit({ message: "deploy", all: true }),
git.$command.push({ force: false })
);
console.log(`${deploy}`);
// "git commit --message deploy --all && git push"
deploy.run(); // executes sequentially, stops on failureimport { fromHelpText } from "cli-to-js";
const helpText = `
Usage: mytool [options]
--output <dir> Output directory
--minify Minify output
--watch Watch for changes
`;
const api = fromHelpText("mytool", helpText, { cwd: "/project" });
await api({ output: "dist", minify: true });# TypeScript wrapper to stdout
npx cli-to-js git
# Write to file
npx cli-to-js git -o git.ts
# Plain JavaScript
npx cli-to-js git --js -o git.js
# Include per-subcommand flags
npx cli-to-js git --subcommands -o git.ts
# Type declarations only
npx cli-to-js git --dts -o git.d.ts
# Dump raw schema as JSON
npx cli-to-js git --jsoncli-to-jsimport { convertCliToJs } from "cli-to-js";
async function agentTask() {
const git = await convertCliToJs("git", { subcommands: true });
const claude = await convertCliToJs("claude");
// Get changed files
const files = await git.diff({ nameOnly: true, _: ["HEAD~1"] }).lines();
for (const file of files) {
// Validate before calling
const errors = claude.$validate({ print: true, model: "sonnet" });
if (errors.length > 0) {
console.error("Invalid flags:", errors);
continue;
}
const review = await claude({
print: true,
model: "sonnet",
_: [`Review ${file} for bugs`],
});
if (!review.stdout.includes("no issues")) {
console.log(`Issues in ${file}:`, review.stdout);
}
}
}const git = await convertCliToJs("git", { subcommands: true });
// Full parsed schema
console.log(git.$schema);
// { binary: "git", command: { name: "git", flags: [...], subcommands: [...] } }
// List subcommands
git.$schema.command.subcommands.forEach((s) => {
console.log(s.name, s.flags.map((f) => f.name));
});const docker = await convertCliToJs("docker", {
cwd: process.env.PROJECT_DIR,
env: { ...process.env, DOCKER_BUILDKIT: "1" },
timeout: 120_000,
});const result = await api({ version: true });
// or
const result = await api("subcommand", { flag: true });const gh = await convertCliToJs("gh");
await gh.auth({ login: true }, { stdio: "inherit" });PATHwhich <binary>fromHelpTexthelpFlag-hhelpconst api = await convertCliToJs("mytool", { helpFlag: "-h" });subcommands: true$parse("sub")await git.$parse("commit"); // now git.$validate("commit", opts) worksconvertCliToJs<T>const api = await convertCliToJs("slow-tool", { timeout: 30_000 });