Files
paseo/packages/cli/tests/07-agent-stop.test.ts
paseo-bot[bot] 05b074764d fix(cli): report an unknown agent ID as AGENT_NOT_FOUND (#6053)
* fix(server): report an unknown agent as not found to CLI commands

fetch_agent_request answered an unknown agent ID with an error string, so
DaemonClient.fetchAgent threw instead of returning null. Every CLI command
that looks up one agent checks for null to report AGENT_NOT_FOUND, so
delete, stop, inspect, logs and the rest reported their generic failure
code and skipped the "paseo ls" hint.

The daemon now answers an unknown agent with a null agent and no error.
An empty or ambiguous identifier is still an error.

* test(cli): expect the not-found message agent logs now prints

* test(cli): move the unknown agent ID cases into the delete and stop suites

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-04 14:55:22 +02:00

161 lines
6.2 KiB
TypeScript

#!/usr/bin/env npx tsx
/**
* Phase 6: Stop Command Tests
*
* Tests the stop command - interrupting agents (no-op if idle) (top-level command).
* Since daemon may not be running, we test both:
* - Help and argument parsing
* - Graceful error handling when daemon not running
* - All flags are accepted
*
* Tests:
* - stop --help shows options
* - stop requires ID, --all, or --cwd
* - stop handles daemon not running
* - stop --all flag is accepted
* - stop --cwd flag is accepted
*/
import assert from "node:assert";
import { getAvailablePort } from "./helpers/network.ts";
import { runPaseoCli, startTestDaemon } from "./helpers/test-daemon.ts";
import { $ } from "zx";
import { mkdtemp, rm } from "fs/promises";
import { tmpdir } from "os";
import { join } from "path";
$.verbose = false;
console.log("=== Stop Command Tests ===\n");
// Allocate an unused endpoint for connection-error and argument-validation checks.
const port = await getAvailablePort();
const paseoHome = await mkdtemp(join(tmpdir(), "paseo-test-home-"));
try {
// Test 1: stop --help shows options
{
console.log("Test 1: stop --help shows options");
const result = await $`npx paseo stop --help`.nothrow();
assert.strictEqual(result.exitCode, 0, "stop --help should exit 0");
assert(result.stdout.includes("--all"), "help should mention --all flag");
assert(result.stdout.includes("--cwd"), "help should mention --cwd option");
assert(result.stdout.includes("--host"), "help should mention --host option");
assert(result.stdout.includes("[id]"), "help should mention optional id argument");
console.log("✓ stop --help shows options\n");
}
// Test 2: stop requires ID, --all, or --cwd
{
console.log("Test 2: stop requires ID, --all, or --cwd");
const result =
await $`PASEO_HOME=${paseoHome} npx paseo --host localhost:${port} stop`.nothrow();
assert.notStrictEqual(result.exitCode, 0, "should fail without id, --all, or --cwd");
const output = result.stdout + result.stderr;
const hasError =
output.toLowerCase().includes("missing") ||
output.toLowerCase().includes("required") ||
output.toLowerCase().includes("argument") ||
output.toLowerCase().includes("id");
assert(hasError, "error should mention missing argument");
console.log("✓ stop requires ID, --all, or --cwd\n");
}
// Test 3: stop handles daemon not running
{
console.log("Test 3: stop handles daemon not running");
const result =
await $`PASEO_HOME=${paseoHome} npx paseo --host localhost:${port} stop abc123`.nothrow();
// Should fail because daemon not running
assert.notStrictEqual(result.exitCode, 0, "should fail when daemon not running");
const output = result.stdout + result.stderr;
const hasError =
output.toLowerCase().includes("daemon") ||
output.toLowerCase().includes("connect") ||
output.toLowerCase().includes("cannot");
assert(hasError, "error message should mention connection issue");
console.log("✓ stop handles daemon not running\n");
}
// Test 4: stop --all flag is accepted
{
console.log("Test 4: stop --all flag is accepted");
const result =
await $`PASEO_HOME=${paseoHome} npx paseo --host localhost:${port} stop --all`.nothrow();
const output = result.stdout + result.stderr;
assert(!output.includes("unknown option"), "should accept --all flag");
assert(!output.includes("error: option"), "should not have option parsing error");
console.log("✓ stop --all flag is accepted\n");
}
// Test 5: stop --cwd flag is accepted
{
console.log("Test 5: stop --cwd flag is accepted");
const result =
await $`PASEO_HOME=${paseoHome} npx paseo --host localhost:${port} stop --cwd /tmp`.nothrow();
const output = result.stdout + result.stderr;
assert(!output.includes("unknown option"), "should accept --cwd flag");
assert(!output.includes("error: option"), "should not have option parsing error");
console.log("✓ stop --cwd flag is accepted\n");
}
// Test 6: stop with ID and --host flag is accepted
{
console.log("Test 6: stop with ID and --host flag is accepted");
const result =
await $`PASEO_HOME=${paseoHome} npx paseo --host localhost:${port} stop abc123 --host localhost:${port}`.nothrow();
const output = result.stdout + result.stderr;
assert(!output.includes("unknown option"), "should accept --host flag");
assert(!output.includes("error: option"), "should not have option parsing error");
console.log("✓ stop with ID and --host flag is accepted\n");
}
// Test 7: paseo --help shows stop command
{
console.log("Test 7: paseo --help shows stop command");
const result = await $`npx paseo --help`.nothrow();
assert.strictEqual(result.exitCode, 0, "paseo --help should exit 0");
assert(result.stdout.includes("stop"), "help should mention stop command");
console.log("✓ paseo --help shows stop command\n");
}
// Test 8: -q (quiet) flag is accepted with stop
{
console.log("Test 8: -q (quiet) flag is accepted with stop");
const result =
await $`PASEO_HOME=${paseoHome} npx paseo --host localhost:${port} -q stop abc123`.nothrow();
const output = result.stdout + result.stderr;
assert(!output.includes("unknown option"), "should accept -q flag");
assert(!output.includes("error: option"), "should not have option parsing error");
console.log("✓ -q (quiet) flag is accepted with stop\n");
}
{
console.log("Test 9: stop reports AGENT_NOT_FOUND for an unknown ID");
const daemon = await startTestDaemon();
try {
const result = await runPaseoCli(daemon, [
"agent",
"stop",
"does-not-exist",
"--host",
`127.0.0.1:${daemon.port}`,
"--json",
]);
assert.notStrictEqual(result.exitCode, 0, "stop should fail for an unknown ID");
const { error } = JSON.parse(result.stderr);
assert.strictEqual(error.code, "AGENT_NOT_FOUND", result.stderr);
assert.match(error.details, /paseo ls/);
} finally {
await daemon.stop();
}
console.log("✓ stop reports AGENT_NOT_FOUND for an unknown ID\n");
}
} finally {
// Clean up temp directory
await rm(paseoHome, { recursive: true, force: true });
}
console.log("=== All stop tests passed ===");