Files
paseo/packages/cli/tests/31-loop-schedule.test.ts
Mohamed Boudra be41911083 feat: add loop, schedule, and chat CLI commands (#149)
* Add metrics collection and terminal performance tests

* feat: add loop, schedule, and chat commands with slash-namespaced RPC

Introduce three new server-side features with CLI command groups:

- `paseo loop` — iterative agent execution with verify-check/verify-prompt
- `paseo schedule` — recurring tasks on interval or cron cadence
- `paseo chat` — chat rooms for agent-to-agent coordination

All features use new slash-namespaced RPC methods (e.g. `loop/run`,
`schedule/create`, `chat/post`) instead of flat message types, backed
by file-based persistence and wired through the existing WebSocket
session dispatch.

* test: stabilize loop schedule chat rollout
2026-03-28 00:25:04 +07:00

100 lines
4.1 KiB
TypeScript

#!/usr/bin/env npx tsx
import assert from "node:assert";
import { rm } from "node:fs/promises";
import { createE2ETestContext } from "./helpers/test-daemon.ts";
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
console.log("=== Loop And Schedule Command Tests ===\n");
const ctx = await createE2ETestContext({ timeout: 30000 });
try {
{
console.log("Test 1: schedule create/ls/inspect/pause/resume/delete work");
const created = await ctx.paseo(
["schedule", "create", "Review new PRs", "--every", "5m", "--name", "review-prs", "--json"],
{ timeout: 30000 },
);
assert.strictEqual(created.exitCode, 0, created.stderr);
const createdJson = JSON.parse(created.stdout);
assert.strictEqual(createdJson.name, "review-prs");
assert.strictEqual(createdJson.cadence, "every:5m");
const listed = await ctx.paseo(["schedule", "ls", "--json"]);
assert.strictEqual(listed.exitCode, 0, listed.stderr);
const listedJson = JSON.parse(listed.stdout);
assert(Array.isArray(listedJson), listed.stdout);
assert(listedJson.some((item: { id: string }) => item.id === createdJson.id), listed.stdout);
const inspected = await ctx.paseo(["schedule", "inspect", createdJson.id, "--json"]);
assert.strictEqual(inspected.exitCode, 0, inspected.stderr);
const inspectedJson = JSON.parse(inspected.stdout);
assert.strictEqual(inspectedJson.status, "active");
assert.strictEqual(inspectedJson.prompt, "Review new PRs");
const paused = await ctx.paseo(["schedule", "pause", createdJson.id, "--json"]);
assert.strictEqual(paused.exitCode, 0, paused.stderr);
assert.strictEqual(JSON.parse(paused.stdout).status, "paused");
const resumed = await ctx.paseo(["schedule", "resume", createdJson.id, "--json"]);
assert.strictEqual(resumed.exitCode, 0, resumed.stderr);
assert.strictEqual(JSON.parse(resumed.stdout).status, "active");
const deleted = await ctx.paseo(["schedule", "delete", createdJson.id, "--json"]);
assert.strictEqual(deleted.exitCode, 0, deleted.stderr);
assert.strictEqual(JSON.parse(deleted.stdout).id, createdJson.id);
console.log("schedule commands work\n");
}
{
console.log("Test 2: loop run/ls/inspect/logs/stop work");
const run = await ctx.paseo(
["loop", "run", "Return any response", "--name", "smoke-loop", "--verify-check", "true", "--json"],
{ timeout: 30000 },
);
assert.strictEqual(run.exitCode, 0, run.stderr);
const runJson = JSON.parse(run.stdout);
assert.strictEqual(runJson.name, "smoke-loop");
const listed = await ctx.paseo(["loop", "ls", "--json"]);
assert.strictEqual(listed.exitCode, 0, listed.stderr);
const listedJson = JSON.parse(listed.stdout);
assert(Array.isArray(listedJson), listed.stdout);
assert(listedJson.some((item: { id: string }) => item.id === runJson.id), listed.stdout);
let status = "running";
for (let attempt = 0; attempt < 40; attempt += 1) {
const inspect = await ctx.paseo(["loop", "inspect", runJson.id, "--json"]);
assert.strictEqual(inspect.exitCode, 0, inspect.stderr);
const inspectJson = JSON.parse(inspect.stdout);
status = inspectJson.status;
if (status !== "running") {
assert.strictEqual(status, "succeeded", inspect.stdout);
break;
}
await sleep(250);
}
assert.strictEqual(status, "succeeded");
const logs = await ctx.paseo(["loop", "logs", runJson.id], { timeout: 15000 });
assert.strictEqual(logs.exitCode, 0, logs.stderr);
assert(logs.stdout.includes("verify-check"), logs.stdout);
const stopped = await ctx.paseo(["loop", "stop", runJson.id, "--json"]);
assert.strictEqual(stopped.exitCode, 0, stopped.stderr);
const stoppedJson = JSON.parse(stopped.stdout);
assert(["succeeded", "stopped"].includes(stoppedJson.status), stopped.stdout);
console.log("loop commands work\n");
}
} finally {
await ctx.stop();
await rm(ctx.paseoHome, { recursive: true, force: true });
await rm(ctx.workDir, { recursive: true, force: true });
}
console.log("=== Loop And Schedule Command Tests Passed ===");