diff --git a/src/commands/agents.ts b/src/commands/agents.ts index 1356456..7362dae 100644 --- a/src/commands/agents.ts +++ b/src/commands/agents.ts @@ -15,6 +15,11 @@ interface Agent { const agentsList = new Command("list") .description("List agents") .option("--json", "Output raw JSON") + .addHelpText("after", ` +Examples: + $ delega agents list + $ delega agents list --json Output as JSON (for scripting) +`) .action(async (opts) => { const data = await apiCall("GET", "/agents"); @@ -46,6 +51,12 @@ const agentsCreate = new Command("create") .argument("", "Agent name") .option("--display-name ", "Friendly display name") .option("--json", "Output raw JSON") + .addHelpText("after", ` +Examples: + $ delega agents create my-agent + $ delega agents create deploy-bot --display-name "Deploy Bot" + $ delega agents create ci-agent --json Get agent details (incl. API key) as JSON +`) .action(async (name: string, opts) => { const body: Record = { name }; if (opts.displayName) body.display_name = opts.displayName; @@ -74,20 +85,52 @@ const agentsCreate = new Command("create") const agentsRotate = new Command("rotate") .description("Rotate an agent's API key") .argument("", "Agent ID") - .action(async (id: string) => { - const yes = await confirm( - `Rotate key for agent ${id}? Old key will stop working immediately. (y/N) `, - ); - if (!yes) { - console.log("Cancelled."); + .option("-y, --yes", "Skip confirmation prompt") + .option("--json", "Output raw JSON") + .option("--dry-run", "Show what would happen without rotating") + .addHelpText("after", ` +Examples: + $ delega agents rotate abc123 + $ delega agents rotate abc123 --yes Skip confirmation (for scripts/agents) + $ delega agents rotate abc123 --json Get new API key as JSON + $ delega agents rotate abc123 --dry-run Preview without rotating +`) + .action(async (id: string, opts) => { + if (opts.dryRun) { + let agent: Agent | undefined; + try { + agent = await apiCall("GET", `/agents/${id}`); + } catch { + // Graceful degradation: if GET fails, just show the ID + } + if (opts.json) { + console.log(JSON.stringify({ dry_run: true, agent_id: id, agent_name: agent?.name ?? null, action: "rotate-key" }, null, 2)); + return; + } + const display = agent?.name ? `${agent.name} (${id})` : id; + console.log(`Would rotate API key for agent ${display}. Old key would stop working immediately.`); return; } + if (!opts.yes) { + const ok = await confirm( + `Rotate key for agent ${id}? Old key will stop working immediately. (y/N) `, + ); + if (!ok) { + console.log("Cancelled."); + return; + } + } - const result = await apiCall<{ api_key: string }>( + const result = await apiCall<{ id: string; api_key: string }>( "POST", `/agents/${id}/rotate-key`, ); + if (opts.json) { + console.log(JSON.stringify({ id: result.id, api_key: result.api_key }, null, 2)); + return; + } + console.log(); console.log(` New API Key: ${chalk.cyan.bold(result.api_key)}`); console.log(chalk.yellow(" Save this key — it will not be shown again.")); diff --git a/src/commands/login.ts b/src/commands/login.ts index 3fa435d..b429cc4 100644 --- a/src/commands/login.ts +++ b/src/commands/login.ts @@ -43,6 +43,11 @@ async function promptSecret(question: string): Promise { export const loginCommand = new Command("login") .description("Authenticate with the Delega API") + .addHelpText("after", ` +Examples: + $ delega login Interactive API key prompt + $ DELEGA_API_KEY=dlg_xxx delega whoami Authenticate via env var instead +`) .action(async () => { printBanner(); diff --git a/src/commands/reset.ts b/src/commands/reset.ts index 352a000..1c0e97e 100644 --- a/src/commands/reset.ts +++ b/src/commands/reset.ts @@ -9,7 +9,35 @@ import { confirm } from "../ui.js"; export const resetCommand = new Command("reset") .description("Remove local credentials and config") .option("--force", "Skip confirmation prompt") + .option("--dry-run", "Show what would be cleaned without doing it") + .option("--json", "Output raw JSON") + .addHelpText("after", ` +Examples: + $ delega reset Interactive confirmation + $ delega reset --force Skip confirmation (for scripts/agents) + $ delega reset --dry-run Preview what would be removed + $ delega reset --dry-run --json Preview as JSON (for scripting) + $ delega reset --force --json Reset and output result as JSON +`) .action(async (opts) => { + const configDir = node_path.join(node_os.homedir(), ".delega"); + + if (opts.dryRun) { + const hasConfig = node_fs.existsSync(configDir); + if (opts.json) { + console.log(JSON.stringify({ dry_run: true, would_remove: { api_key: true, config_dir: hasConfig ? configDir : null } }, null, 2)); + return; + } + console.log("Dry run — the following would be removed:"); + console.log(` - API key from secure storage (if stored)`); + if (hasConfig) { + console.log(` - ${configDir}`); + } else { + console.log(` - ${configDir} (not found)`); + } + return; + } + if (!opts.force) { const yes = await confirm( "This will remove your stored API key and config. Continue? (y/N) ", @@ -24,7 +52,6 @@ export const resetCommand = new Command("reset") const keyDeleted = deleteStoredApiKey(); // 2. Delete ~/.delega/ directory - const configDir = node_path.join(node_os.homedir(), ".delega"); let configDeleted = false; if (node_fs.existsSync(configDir)) { node_fs.rmSync(configDir, { recursive: true, force: true }); @@ -32,6 +59,11 @@ export const resetCommand = new Command("reset") } // 3. Report what was cleaned + if (opts.json) { + console.log(JSON.stringify({ api_key_removed: keyDeleted, config_dir_removed: configDeleted ? configDir : null }, null, 2)); + return; + } + if (keyDeleted) console.log(chalk.green("✓ API key removed from secure storage")); if (configDeleted) console.log(chalk.green(`✓ Removed ${configDir}`)); if (!keyDeleted && !configDeleted) { diff --git a/src/commands/stats.ts b/src/commands/stats.ts index ccf2c51..e5ad7e3 100644 --- a/src/commands/stats.ts +++ b/src/commands/stats.ts @@ -14,6 +14,11 @@ interface Stats { export const statsCommand = new Command("stats") .description("Show usage statistics") .option("--json", "Output raw JSON") + .addHelpText("after", ` +Examples: + $ delega stats + $ delega stats --json Output as JSON (for scripting) +`) .action(async (opts) => { const data = await apiCall("GET", "/stats"); diff --git a/src/commands/status.ts b/src/commands/status.ts index 2f1ce2a..94e5aa8 100644 --- a/src/commands/status.ts +++ b/src/commands/status.ts @@ -32,6 +32,11 @@ interface Stats { export const statusCommand = new Command("status") .description("Check connection and show environment info") .option("--json", "Output raw JSON") + .addHelpText("after", ` +Examples: + $ delega status + $ delega status --json Output as JSON (for scripting) +`) .action(async (opts) => { // 1. Check for API key (non-fatal — we can still show health info) const apiKey = getApiKey(); diff --git a/src/commands/tasks.ts b/src/commands/tasks.ts index 6c176fa..fd33efc 100644 --- a/src/commands/tasks.ts +++ b/src/commands/tasks.ts @@ -38,6 +38,14 @@ const tasksList = new Command("list") .option("--completed", "Include completed tasks") .option("--limit ", "Limit results", parseInt) .option("--json", "Output raw JSON") + .addHelpText("after", ` +Examples: + $ delega tasks list List pending tasks + $ delega tasks list --completed Include completed tasks + $ delega tasks list --limit 5 Show only 5 tasks + $ delega tasks list --json Output as JSON (for scripting) + $ delega tasks list --json | jq '.[0]' Get first task with jq +`) .action(async (opts) => { let path = "/tasks"; const params: string[] = []; @@ -78,6 +86,14 @@ const tasksCreate = new Command("create") .option("--labels ", "Comma-separated labels") .option("--due ", "Due date (YYYY-MM-DD)") .option("--json", "Output raw JSON") + .addHelpText("after", ` +Examples: + $ delega tasks create "Fix login bug" + $ delega tasks create "Deploy v2" --priority 1 + $ delega tasks create "Write tests" --labels "testing,backend" + $ delega tasks create "Ship feature" --due 2025-12-31 + $ delega tasks create "Audit deps" --json Get created task as JSON +`) .action(async (content: string, opts) => { const body: Record = { content }; if (opts.priority) body.priority = opts.priority; @@ -103,6 +119,11 @@ const tasksShow = new Command("show") .description("Show task details") .argument("", "Task ID") .option("--json", "Output raw JSON") + .addHelpText("after", ` +Examples: + $ delega tasks show abc123 + $ delega tasks show abc123 --json Get full task details as JSON +`) .action(async (id: string, opts) => { const task = await apiCall("GET", `/tasks/${id}`); @@ -141,21 +162,56 @@ const tasksShow = new Command("show") const tasksComplete = new Command("complete") .description("Mark a task as completed") .argument("", "Task ID") - .action(async (id: string) => { - await apiCall("POST", `/tasks/${id}/complete`); + .option("--json", "Output raw JSON") + .addHelpText("after", ` +Examples: + $ delega tasks complete abc123 + $ delega tasks complete abc123 --json Get completed task as JSON +`) + .action(async (id: string, opts) => { + const task = await apiCall("POST", `/tasks/${id}/complete`); + if (opts.json) { + console.log(JSON.stringify(task, null, 2)); + return; + } console.log(`Task ${id} completed.`); }); const tasksDelete = new Command("delete") .description("Delete a task") .argument("", "Task ID") - .action(async (id: string) => { - const yes = await confirm(`Delete task ${id}? (y/N) `); - if (!yes) { - console.log("Cancelled."); + .option("-y, --yes", "Skip confirmation prompt") + .option("--json", "Output raw JSON") + .option("--dry-run", "Show what would be deleted without doing it") + .addHelpText("after", ` +Examples: + $ delega tasks delete abc123 + $ delega tasks delete abc123 --yes Skip confirmation (for scripts/agents) + $ delega tasks delete abc123 --json Output result as JSON + $ delega tasks delete abc123 --dry-run Preview without deleting +`) + .action(async (id: string, opts) => { + if (opts.dryRun) { + const task = await apiCall("GET", `/tasks/${id}`); + if (opts.json) { + console.log(JSON.stringify({ dry_run: true, would_delete: task }, null, 2)); + return; + } + console.log(`Would delete task ${id}: ${task.content}`); return; } + if (!opts.yes) { + const ok = await confirm(`Delete task ${id}? (y/N) `); + if (!ok) { + console.log("Cancelled."); + return; + } + } await apiCall("DELETE", `/tasks/${id}`); + if (opts.json) { + console.log(JSON.stringify({ id, deleted: true }, null, 2)); + return; + } console.log(`Task ${id} deleted.`); }); @@ -164,11 +220,21 @@ const tasksDelegate = new Command("delegate") .argument("", "Task ID") .argument("", "Agent ID to delegate to") .requiredOption("--content ", "Subtask description (required)") + .option("--json", "Output raw JSON") + .addHelpText("after", ` +Examples: + $ delega tasks delegate abc123 agent456 --content "Handle the frontend" + $ delega tasks delegate abc123 agent456 --content "Run tests" --json +`) .action(async (taskId: string, agentId: string, opts) => { const body: Record = { assigned_to_agent_id: agentId }; if (opts.content) body.content = opts.content; - await apiCall("POST", `/tasks/${taskId}/delegate`, body); + const subtask = await apiCall("POST", `/tasks/${taskId}/delegate`, body); + if (opts.json) { + console.log(JSON.stringify(subtask, null, 2)); + return; + } console.log(`Task delegated to ${agentId}.`); }); diff --git a/src/commands/whoami.ts b/src/commands/whoami.ts index a97e0d0..d392ef1 100644 --- a/src/commands/whoami.ts +++ b/src/commands/whoami.ts @@ -25,6 +25,10 @@ interface MeResponse { export const whoamiCommand = new Command("whoami") .description("Show current authenticated agent") + .addHelpText("after", ` +Examples: + $ delega whoami Show current agent identity +`) .action(async () => { const me = await apiRequest("GET", "/agent/me"); if (me.ok) {