AkurAI Build
Menu

popagent

public

Latest change 49c9a971df21b51e0662c9d8945b7f7a8af80368 - Add durable Popagent agent CLI by Ólafur Búi Ólafsson

#!/usr/bin/env bun

const baseUrl = (process.env.POPAGENT_URL ?? "http://127.0.0.1:5180").replace(/\/$/, "");
const [command = "help", ...args] = Bun.argv.slice(2);

const usage = `Usage: popagent <command> [arguments]

One-shot commands:
  popagent help
  popagent api <METHOD> <path> [json]
  popagent agents
  popagent skills <agent>
  popagent workspaces
  popagent tasks [workspace]
  popagent task-create <workspace> <prompt> [model]
  popagent task-cancel <task-id>

Environment:
  POPAGENT_URL      API base URL (default: http://127.0.0.1:5180)
  POPAGENT_API_KEY  Sent only as x-popagent-key; never printed
`;

function fail(message: string): never {
  console.error(`popagent: ${message}`);
  process.exit(2);
}

async function api(method: string, path: string, body?: string): Promise<void> {
  if (!path.startsWith("/api/")) fail("path must begin with /api/");
  const headers: Record<string, string> = {};
  if (process.env.POPAGENT_API_KEY) headers["x-popagent-key"] = process.env.POPAGENT_API_KEY;
  if (body !== undefined) headers["content-type"] = "application/json";
  const response = await fetch(`${baseUrl}${path}`, { method, headers, body });
  const text = await response.text();
  if (text) console.log(text);
  if (!response.ok) process.exit(1);
}

switch (command) {
  case "help":
  case "--help":
  case "-h":
    console.log(usage);
    break;
  case "api": {
    const [method, path, body] = args;
    if (!method || !path) fail("api requires METHOD and path");
    await api(method.toUpperCase(), path, body);
    break;
  }
  case "agents": await api("GET", "/api/agents"); break;
  case "skills": {
    const [agent] = args;
    if (!agent) fail("skills requires an agent id");
    await api("GET", `/api/agents/${encodeURIComponent(agent)}/skills`);
    break;
  }
  case "workspaces": await api("GET", "/api/workspaces"); break;
  case "tasks": {
    const [workspace] = args;
    await api("GET", `/api/tasks${workspace ? `?workspaceId=${encodeURIComponent(workspace)}` : ""}`);
    break;
  }
  case "task-create": {
    const [workspaceId, prompt, model] = args;
    if (!workspaceId || !prompt) fail("task-create requires workspace and prompt");
    await api("POST", "/api/tasks", JSON.stringify({ workspaceId, prompt, ...(model ? { model } : {}) }));
    break;
  }
  case "task-cancel": {
    const [id] = args;
    if (!id) fail("task-cancel requires a task id");
    await api("POST", `/api/tasks/${encodeURIComponent(id)}/cancel`);
    break;
  }
  default: fail(`unknown command: ${command}\n\n${usage}`);
}