AkurAI Build
Menu

popagent

public

Latest change ec66504a301a4150cf6cd2203554901a84fdc769 - Complete repository brief integration and CI deployment by AkurAI Build

import { describe, expect, test } from "bun:test";

const run = async (args: string[], url?: string) => {
  const process = Bun.spawn(["./popagent", ...args], {
    stdout: "pipe",
    stderr: "pipe",
    env: { ...Bun.env, ...(url ? { POPAGENT_URL: url } : {}) },
  });
  return {
    exitCode: await process.exited,
    stdout: await new Response(process.stdout).text(),
    stderr: await new Response(process.stderr).text(),
  };
};

describe("popagent CLI", () => {
  test("gives AI agents a complete one-shot command index", async () => {
    const result = await run(["help"]);
    expect(result.exitCode).toBe(0);
    expect(result.stderr).toBe("");
    for (const command of [
      "popagent agent-update <agent> <json>",
      "popagent skill-create <agent> <json>",
      "popagent workspace-create <json>",
      "popagent task-resolve <task-id> <json>",
      "popagent signals [limit]",
      "popagent automation-status",
      "popagent automation-run <workspace>",
      "popagent signal-ignore <signal-id>",
      "popagent signal-retry <signal-id>",
      "popagent doc-save <workspace> <json>",
      "popagent repo-brief <workspace> <query>",
      "popagent docs-reindex <workspace>",
      "popagent task-create <workspace> <prompt> [model]",
      "popagent task-delete <task-id>",
      "popagent schedule-create <json>",
      "popagent settings-update <section> <json>",
      "popagent api <METHOD> <path> [json]",
    ]) expect(result.stdout).toContain(command);
    expect(result.stdout).toContain("POPAGENT_URL");
    expect(result.stdout).toContain("x-popagent-key");
    expect(result.stdout).toContain("JSON arguments are passed unchanged");
  });

  test("routes named management commands without rewriting JSON", async () => {
    const requests: Array<{ method: string; path: string; body: string }> = [];
    const server = Bun.serve({
      port: 0,
      async fetch(request) {
        requests.push({
          method: request.method,
          path: new URL(request.url).pathname,
          body: await request.text(),
        });
        return Response.json({ ok: true });
      },
    });
    try {
      const body = '{"path":"guides/start.md","content":"# Start"}';
      const result = await run(["doc-save", "team/a", body], server.url.toString());
      expect(result.exitCode).toBe(0);
      expect(JSON.parse(result.stdout)).toEqual({ ok: true });
      expect(requests).toEqual([{
        method: "POST",
        path: "/api/workspaces/team%2Fa/docs",
        body,
      }]);
    } finally {
      server.stop(true);
    }
  });

  test("routes repository briefs through the workspace API", async () => {
    const requests: Array<{ method: string; path: string }> = [];
    const server = Bun.serve({
      port: 0,
      fetch(request) {
        requests.push({ method: request.method, path: new URL(request.url).pathname + new URL(request.url).search });
        return Response.json({ candidates: [] });
      },
    });
    try {
      expect((await run(["repo-brief", "team/a", "fix payment"], server.url.toString())).exitCode).toBe(0);
      expect(requests).toEqual([{
        method: "GET",
        path: "/api/workspaces/team%2Fa/repo-brief?q=fix%20payment",
      }]);
    } finally {
      server.stop(true);
    }
  });

  test("routes terminal task resolution evidence", async () => {
    const requests: Array<{ method: string; path: string; body: string }> = [];
    const server = Bun.serve({
      port: 0,
      async fetch(request) {
        requests.push({ method: request.method, path: new URL(request.url).pathname, body: await request.text() });
        return Response.json({ status: "completed" });
      },
    });
    try {
      const body = '{"output":"Reviewed inline"}';
      const result = await run(["task-resolve", "failed/task", body], server.url.toString());
      expect(result.exitCode).toBe(0);
      expect(requests).toEqual([{ method: "POST", path: "/api/tasks/failed%2Ftask/resolve", body }]);
    } finally {
      server.stop(true);
    }
  });

  test("routes signal inspection and management commands", async () => {
    const requests: Array<{ method: string; path: string }> = [];
    const server = Bun.serve({
      port: 0,
      fetch(request) {
        requests.push({ method: request.method, path: new URL(request.url).pathname + new URL(request.url).search });
        return Response.json({ ok: true });
      },
    });
    try {
      expect((await run(["signals", "25"], server.url.toString())).exitCode).toBe(0);
      expect((await run(["signal-ignore", "signal/id"], server.url.toString())).exitCode).toBe(0);
      expect((await run(["signal-retry", "signal/id"], server.url.toString())).exitCode).toBe(0);
      expect(requests).toEqual([
        { method: "GET", path: "/api/autonomy/signals?limit=25" },
        { method: "POST", path: "/api/autonomy/signals/signal%2Fid/ignore" },
        { method: "POST", path: "/api/autonomy/signals/signal%2Fid/retry" },
      ]);
    } finally {
      server.stop(true);
    }
  });
});