mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-06 16:34:36 +00:00
fix(cli): fail agent open for an agent the daemon does not have (#5727)
paseo agent open launched Desktop with whatever string it was given, printed "opened" and exited 0, so a bad ID moved the user to a broken "Agent not found" tab and the calling script saw success. Look the agent up on the daemon first, the way inspect and mode do, and open Desktop on the ID the daemon resolved. Closes #5721 Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type { Command } from "commander";
|
||||
import { connectToDaemon } from "../../utils/client.js";
|
||||
import type { AgentDeepLinkTarget } from "@getpaseo/protocol/agent-deep-link";
|
||||
import { openDesktopWithAgent } from "../open.js";
|
||||
import type {
|
||||
CommandError,
|
||||
@@ -30,10 +31,21 @@ export function addOpenOptions(command: Command): Command {
|
||||
.option("--server <server-id>", "Server ID (defaults to the local daemon)");
|
||||
}
|
||||
|
||||
async function resolveServerId(options: CommandOptions): Promise<string> {
|
||||
function toOpenError(err: unknown): CommandError {
|
||||
if (err && typeof err === "object" && "code" in err) {
|
||||
return err as CommandError;
|
||||
}
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
return { code: "OPEN_FAILED", message: `Failed to open agent: ${message}` };
|
||||
}
|
||||
|
||||
async function resolveAgentTarget(
|
||||
agentId: string,
|
||||
options: CommandOptions,
|
||||
): Promise<AgentDeepLinkTarget> {
|
||||
const explicitServerId = typeof options.server === "string" ? options.server.trim() : "";
|
||||
if (explicitServerId) {
|
||||
return explicitServerId;
|
||||
return { serverId: explicitServerId, agentId };
|
||||
}
|
||||
|
||||
const client = await connectToDaemon({ target: options.daemonTarget });
|
||||
@@ -46,7 +58,19 @@ async function resolveServerId(options: CommandOptions): Promise<string> {
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
return serverId;
|
||||
|
||||
const fetchResult = await client.fetchAgent({ agentId });
|
||||
if (!fetchResult) {
|
||||
const error: CommandError = {
|
||||
code: "AGENT_NOT_FOUND",
|
||||
message: `Agent not found: ${agentId}`,
|
||||
details: 'Use "paseo ls" to list available agents',
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
return { serverId, agentId: fetchResult.agent.id };
|
||||
} catch (err) {
|
||||
throw toOpenError(err);
|
||||
} finally {
|
||||
await client.close().catch(() => {});
|
||||
}
|
||||
@@ -66,12 +90,12 @@ export async function runOpenCommand(
|
||||
throw error;
|
||||
}
|
||||
|
||||
const serverId = await resolveServerId(options);
|
||||
await openDesktopWithAgent({ serverId, agentId });
|
||||
const target = await resolveAgentTarget(agentId, options);
|
||||
await openDesktopWithAgent(target);
|
||||
|
||||
return {
|
||||
type: "single",
|
||||
data: { agentId, serverId, status: "opened" },
|
||||
data: { ...target, status: "opened" },
|
||||
schema: openAgentSchema,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
|
||||
import assert from "node:assert";
|
||||
import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { runPaseoCli, startTestDaemon } from "./helpers/test-daemon.ts";
|
||||
|
||||
console.log("=== Agent Open Command Tests ===\n");
|
||||
|
||||
if (process.platform !== "linux") {
|
||||
console.log("Skipped: the fake Desktop app is a Linux AppImage path.");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const daemon = await startTestDaemon();
|
||||
|
||||
// runPaseoCli sets HOME to the daemon's home, where the CLI looks for
|
||||
// ~/Applications/Paseo.AppImage on Linux. The fake app records its launch.
|
||||
const launchRecord = join(daemon.paseoHome, "desktop-launches.txt");
|
||||
const fakeDesktop = join(daemon.paseoHome, "Applications", "Paseo.AppImage");
|
||||
await mkdir(join(daemon.paseoHome, "Applications"), { recursive: true });
|
||||
await writeFile(fakeDesktop, `#!/bin/sh\necho "$@" >> "${launchRecord}"\n`);
|
||||
await chmod(fakeDesktop, 0o755);
|
||||
|
||||
try {
|
||||
{
|
||||
console.log("Test 1: an unknown agent ID fails without opening Desktop");
|
||||
const result = await runPaseoCli(daemon, [
|
||||
"agent",
|
||||
"open",
|
||||
"does-not-exist",
|
||||
"--host",
|
||||
`127.0.0.1:${daemon.port}`,
|
||||
"--json",
|
||||
]);
|
||||
|
||||
assert.notStrictEqual(result.exitCode, 0, "open should fail for an unknown agent");
|
||||
assert.match(JSON.parse(result.stderr).error.message, /Agent not found: does-not-exist/);
|
||||
// Give a wrongly spawned detached app time to write its record.
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
assert.ok(
|
||||
!existsSync(launchRecord),
|
||||
`Desktop should not open, but was launched with: ${existsSync(launchRecord) ? await readFile(launchRecord, "utf8") : ""}`,
|
||||
);
|
||||
console.log("✓ unknown agent ID fails without opening Desktop\n");
|
||||
}
|
||||
} finally {
|
||||
await daemon.stop();
|
||||
}
|
||||
|
||||
console.log("=== All agent open tests passed ===");
|
||||
Reference in New Issue
Block a user