mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-23 17:52:49 +00:00
199 lines
7.9 KiB
TypeScript
199 lines
7.9 KiB
TypeScript
import { pairCommand } from "./commands/daemon/pair.js";
|
|
import { Command, Option } from "commander";
|
|
import { createAgentCommand } from "./commands/agent/index.js";
|
|
import { createDaemonCommand } from "./commands/daemon/index.js";
|
|
import { createPermitCommand } from "./commands/permit/index.js";
|
|
import { createUsageCommand } from "./commands/usage/index.js";
|
|
import { createProviderCommand } from "./commands/provider/index.js";
|
|
import { createPluginCommand } from "./commands/plugin/index.js";
|
|
import { createProjectCommand } from "./commands/project/index.js";
|
|
import { createScheduleCommand } from "./commands/schedule/index.js";
|
|
import { createSpeechCommand } from "./commands/speech/index.js";
|
|
import { createScriptCommand } from "./commands/script/index.js";
|
|
import { createTerminalCommand } from "./commands/terminal/index.js";
|
|
import { createWorktreeCommand } from "./commands/worktree/index.js";
|
|
import { createWorkspaceCommand } from "./commands/workspace/index.js";
|
|
import { createHeartbeatCommand } from "./commands/heartbeat/index.js";
|
|
import { createHubCommand } from "./commands/hub/index.js";
|
|
import { createHooksCommand } from "./commands/hooks.js";
|
|
import { startCommand as daemonStartCommand } from "./commands/daemon/start.js";
|
|
import { daemonStatusCommand } from "./commands/daemon/status.js";
|
|
import { daemonRestartCommand } from "./commands/daemon/restart.js";
|
|
import { daemonReloadCommand } from "./commands/daemon/reload.js";
|
|
import { addLsOptions, runLsCommand } from "./commands/agent/ls.js";
|
|
import { addRunOptions, runRunCommand } from "./commands/agent/run.js";
|
|
import { addLogsOptions, runLogsCommand } from "./commands/agent/logs.js";
|
|
import { addDeleteOptions, runDeleteCommand } from "./commands/agent/delete.js";
|
|
import { addStopOptions, runStopCommand } from "./commands/agent/stop.js";
|
|
import { addSendOptions, runSendCommand } from "./commands/agent/send.js";
|
|
import { addInspectOptions, runInspectCommand } from "./commands/agent/inspect.js";
|
|
import { addWaitOptions, runWaitCommand } from "./commands/agent/wait.js";
|
|
import { addArchiveOptions, runArchiveCommand } from "./commands/agent/archive.js";
|
|
import { addAttachOptions, runAttachCommand } from "./commands/agent/attach.js";
|
|
import { addImportOptions, runImportCommand } from "./commands/agent/import.js";
|
|
import { withOutput } from "./output/index.js";
|
|
import { runCloneCommand } from "./commands/clone.js";
|
|
import { onboardCommand } from "./commands/onboard.js";
|
|
import {
|
|
addDaemonHostOption,
|
|
addJsonAndDaemonHostOptions,
|
|
withGlobalOptions,
|
|
} from "./utils/command-options.js";
|
|
import { resolveCliVersion } from "./version.js";
|
|
|
|
const VERSION = resolveCliVersion();
|
|
|
|
export function createCli(): Command {
|
|
const program = new Command();
|
|
|
|
program
|
|
.name("paseo")
|
|
.description("Paseo CLI - control your AI coding agents from the command line")
|
|
.version(VERSION, "-v, --version", "output the version number")
|
|
// Global output options
|
|
.option("-o, --format <format>", "output format: table, json, yaml", "table")
|
|
.option("--json", "output in JSON format (alias for --format json)")
|
|
.option("-q, --quiet", "minimal output (IDs only)")
|
|
.option("--no-headers", "omit table headers")
|
|
.option("--no-color", "disable colored output");
|
|
addDaemonHostOption(program);
|
|
|
|
// Primary agent commands (top-level)
|
|
addJsonAndDaemonHostOptions(addLsOptions(program.command("ls"))).action(withOutput(runLsCommand));
|
|
|
|
addJsonAndDaemonHostOptions(addRunOptions(program.command("run"))).action(
|
|
withOutput(runRunCommand),
|
|
);
|
|
|
|
addJsonAndDaemonHostOptions(addImportOptions(program.command("import"))).action(
|
|
withOutput(runImportCommand),
|
|
);
|
|
|
|
addJsonAndDaemonHostOptions(
|
|
program
|
|
.command("clone")
|
|
.description("Clone a GitHub repo and register it as a Paseo workspace")
|
|
.argument("<repo>", "GitHub repo in owner/repo format or a full git remote URL")
|
|
.requiredOption("--dir <path>", "Parent directory to clone into (for example: ~/workspace)"),
|
|
)
|
|
.addOption(
|
|
new Option("--protocol <protocol>", "Protocol for owner/repo shorthand repositories").choices(
|
|
["https", "ssh"],
|
|
),
|
|
)
|
|
.action(withOutput(runCloneCommand));
|
|
|
|
addDaemonHostOption(addAttachOptions(program.command("attach"))).action(
|
|
withGlobalOptions(runAttachCommand),
|
|
);
|
|
|
|
addDaemonHostOption(addLogsOptions(program.command("logs"))).action(
|
|
withGlobalOptions(runLogsCommand),
|
|
);
|
|
|
|
addJsonAndDaemonHostOptions(addStopOptions(program.command("stop"))).action(
|
|
withOutput(runStopCommand),
|
|
);
|
|
|
|
addJsonAndDaemonHostOptions(addDeleteOptions(program.command("delete"))).action(
|
|
withOutput(runDeleteCommand),
|
|
);
|
|
|
|
addJsonAndDaemonHostOptions(addSendOptions(program.command("send"))).action(
|
|
withOutput(runSendCommand),
|
|
);
|
|
|
|
addJsonAndDaemonHostOptions(addInspectOptions(program.command("inspect"))).action(
|
|
withOutput(runInspectCommand),
|
|
);
|
|
|
|
addJsonAndDaemonHostOptions(addWaitOptions(program.command("wait"))).action(
|
|
withOutput(runWaitCommand),
|
|
);
|
|
|
|
addJsonAndDaemonHostOptions(addArchiveOptions(program.command("archive"))).action(
|
|
withOutput(runArchiveCommand),
|
|
);
|
|
|
|
// Top-level local daemon shortcuts
|
|
program.addCommand(onboardCommand());
|
|
program.addCommand(daemonStartCommand());
|
|
program.addCommand(createHooksCommand());
|
|
|
|
program.addCommand(daemonStatusCommand());
|
|
program.addCommand(daemonRestartCommand());
|
|
program.addCommand(daemonReloadCommand());
|
|
program.addCommand(pairCommand());
|
|
|
|
// Advanced agent commands (less common operations)
|
|
program.addCommand(createAgentCommand());
|
|
|
|
// Daemon commands
|
|
program.addCommand(createDaemonCommand());
|
|
program.addCommand(createHubCommand());
|
|
|
|
// Chat commands
|
|
|
|
// Terminal commands
|
|
program.addCommand(createTerminalCommand());
|
|
|
|
// Workspace script commands
|
|
program.addCommand(createScriptCommand());
|
|
|
|
// Schedule commands
|
|
program.addCommand(createScheduleCommand());
|
|
program.addCommand(createHeartbeatCommand());
|
|
|
|
// Permission commands
|
|
program.addCommand(createPermitCommand());
|
|
|
|
// Provider commands
|
|
program.addCommand(createProviderCommand());
|
|
program.addCommand(createUsageCommand());
|
|
program.addCommand(createPluginCommand());
|
|
|
|
// Speech model commands
|
|
program.addCommand(createSpeechCommand());
|
|
|
|
// Workspace commands
|
|
program.addCommand(createProjectCommand());
|
|
program.addCommand(createWorkspaceCommand());
|
|
// COMPAT(worktreeCli): legacy command alias added before workspace was the product unit.
|
|
// Added in v0.2.0; remove after 2027-01-17.
|
|
program.addCommand(createWorktreeCommand(), { hidden: true });
|
|
|
|
// Stop root parsing at the command so `plugin update --version` belongs to update.
|
|
// Keep global options available after a command, as they were before positional parsing.
|
|
program.enablePositionalOptions();
|
|
for (const command of program.commands) {
|
|
for (const option of program.options) {
|
|
if (option.long === "--version") continue;
|
|
if (!command.options.some((local) => local.long === option.long)) command.addOption(option);
|
|
if (option.long === "--home" || option.long === "--host") continue;
|
|
command.on(`option:${option.name()}`, () => {
|
|
const key = option.attributeName();
|
|
program.setOptionValueWithSource(key, command.opts()[key], "cli");
|
|
});
|
|
}
|
|
if (command.name() !== "plugin")
|
|
command.version(VERSION, "-v, --version", "output the version number");
|
|
}
|
|
|
|
const enforceSelectorDuplicates = (command: Command) => {
|
|
for (const option of command.options) {
|
|
if (option.long !== "--home" && option.long !== "--host") continue;
|
|
option.argParser((value: string, previous: string | undefined) => {
|
|
if (previous !== undefined && previous !== value)
|
|
throw {
|
|
code: "TARGET_AMBIGUOUS",
|
|
message: `Conflicting duplicate ${option.long} selectors.`,
|
|
};
|
|
return value;
|
|
});
|
|
}
|
|
command.commands.forEach(enforceSelectorDuplicates);
|
|
};
|
|
enforceSelectorDuplicates(program);
|
|
return program;
|
|
}
|