mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-22 09:12:44 +00:00
153 lines
6.8 KiB
TypeScript
153 lines
6.8 KiB
TypeScript
#!/usr/bin/env npx tsx
|
|
import assert from "node:assert/strict";
|
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { createE2ETestContext } from "./helpers/test-daemon.ts";
|
|
import { connectToDaemon } from "../src/utils/client.ts";
|
|
import { resolveCliVersion } from "../src/version.ts";
|
|
|
|
const context = await createE2ETestContext();
|
|
try {
|
|
const directory = join(context.workDir, "usage-plugin");
|
|
await mkdir(directory);
|
|
await writeFile(
|
|
join(directory, "paseo-plugin.json"),
|
|
JSON.stringify({
|
|
id: "cli-usage",
|
|
requirements: { paseo: `>=${resolveCliVersion()}` },
|
|
}),
|
|
);
|
|
await writeFile(
|
|
join(directory, "index.server.ts"),
|
|
`
|
|
import { z } from 'zod';
|
|
export default function contribute(server) {
|
|
const counts = new Map();
|
|
server.registerUsageSource({
|
|
id: 'cli-usage', label: 'CLI usage fixture', input: z.object({ key: z.string() }),
|
|
discover: async () => [
|
|
{ key: 'work.account', label: 'Work', input: { key: 'work' } },
|
|
{ key: 'personal', input: { key: 'personal' } },
|
|
{ key: 'broken', harness: 'Harness A', input: { key: 'rejected' } },
|
|
{ key: 'broken', harness: 'Harness B', input: { key: 'expired' } },
|
|
{ key: 'error', input: { key: 'error' } },
|
|
],
|
|
fetch: async ({key}) => {
|
|
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
if (key === 'rejected') return {status: 'unavailable', problem: {kind: 'rejected', status: 401, refreshedBy: 'codex login'}};
|
|
if (key === 'expired') return {status: 'unavailable', problem: {kind: 'expired', expiresAt: '2026-10-08T00:00:00Z', refreshedBy: 'claude'}};
|
|
if (key === 'error') throw new Error('Quota service failed');
|
|
return { status: 'available', planLabel: 'Pro', windows: [
|
|
{ id: 'session', label: 'Session', usedPct: counts.get(key), remainingPct: 99, resetsAt: '2026-10-09T17:00:00Z', runsOutAt: '2026-10-09T16:00:00Z', shortfallPct: 4.25 },
|
|
{ id: 'weekly', label: 'Weekly', usedPct: null, remainingPct: 0 },
|
|
], balances: [
|
|
{ id: 'credits', label: 'Credits', remaining: 2.5, unit: 'credits' },
|
|
{ id: 'tokens', label: 'Tokens', used: 0, limit: 100, unit: 'tokens' },
|
|
], details: [{ id: 'tier', label: 'Tier', value: 'Enterprise' }] };
|
|
},
|
|
});
|
|
return () => {};
|
|
}`,
|
|
);
|
|
const client = await connectToDaemon({ target: { kind: "instance", home: context.paseoHome } });
|
|
try {
|
|
await client.patchDaemonConfig({ pluginsEnabled: true });
|
|
await client.installDirectoryPlugin(directory, "cli-usage");
|
|
} finally {
|
|
await client.close();
|
|
}
|
|
async function ok(args: string[]) {
|
|
const result = await context.paseo(args);
|
|
assert.equal(result.exitCode, 0, result.stderr);
|
|
assert.equal(result.stderr, "");
|
|
return result.stdout;
|
|
}
|
|
// The first usage request is inspect: no earlier usage discovery has populated known IDs.
|
|
const cold = JSON.parse(await ok(["usage", "inspect", "cli-usage:work.account", "--json"]));
|
|
assert.equal(cold.id, "cli-usage:work.account");
|
|
assert.equal(cold.report.windows[0].usedPct, 1);
|
|
for (const args of [
|
|
["usage", "--agent", "agent-A", "inspect", cold.id, "--json"],
|
|
["usage", "inspect", cold.id, "--agent", "agent-A", "--json"],
|
|
]) {
|
|
const conflicting = await context.paseo(args);
|
|
assert.equal(conflicting.exitCode, 1, `Expected selector rejection: ${args.join(" ")}`);
|
|
assert.equal(conflicting.stdout, "");
|
|
assert.deepEqual(JSON.parse(conflicting.stderr).error, {
|
|
code: "INVALID_OPTIONS",
|
|
message:
|
|
"--agent cannot be combined with usage inspect. Use usage ls --agent <id> for agent account usage, or usage inspect <report-id> for an exact report.",
|
|
});
|
|
}
|
|
|
|
const list = JSON.parse(await ok(["usage", "ls", "--json"]));
|
|
const defaultList = JSON.parse(await ok(["usage", "--json"]));
|
|
assert.deepEqual(defaultList, list);
|
|
assert.deepEqual(list.map((entry: { id: string }) => entry.id).sort(), [
|
|
"cli-usage:broken",
|
|
"cli-usage:error",
|
|
"cli-usage:personal",
|
|
"cli-usage:work.account",
|
|
]);
|
|
const work = list.find((entry: { id: string }) => entry.id === cold.id);
|
|
assert.deepEqual(work, cold);
|
|
const table = await ok(["usage", "ls", "--no-color"]);
|
|
for (const text of [
|
|
"REPORT ID",
|
|
"Credits: - used, 2.5 remaining, - limit (credits)",
|
|
"Tokens: 0 used, - remaining, 100 limit (tokens)",
|
|
"Weekly: - used, 0% remaining",
|
|
"Harness A: Login rejected (HTTP 401). Run codex login",
|
|
"Harness B: Login expired at",
|
|
"Quota service failed",
|
|
])
|
|
assert.ok(table.includes(text), text);
|
|
const quiet = await ok(["usage", "ls", "--quiet"]);
|
|
assert.deepEqual(
|
|
quiet.trim().split("\n").sort(),
|
|
list.map((entry: { id: string }) => entry.id).sort(),
|
|
);
|
|
assert.ok(!(await ok(["usage", "ls", "--no-headers"])).includes("REPORT ID"));
|
|
const detail = await ok(["usage", "inspect", cold.id]);
|
|
for (const text of [
|
|
"Plan: Pro",
|
|
"Resets: 2026-10-09T17:00:00Z",
|
|
"Runs out: 2026-10-09T16:00:00Z",
|
|
"Shortfall: 4.25%",
|
|
"Tier: Enterprise",
|
|
])
|
|
assert.ok(detail.includes(text), text);
|
|
const refreshed = JSON.parse(await ok(["usage", "inspect", cold.id, "--refresh", "--json"]));
|
|
assert.equal(refreshed.report.windows[0].usedPct, 2);
|
|
const personal = JSON.parse(await ok(["usage", "inspect", "cli-usage:personal", "--json"]));
|
|
assert.equal(personal.report.windows[0].usedPct, 1);
|
|
const allRefreshed = JSON.parse(await ok(["usage", "ls", "--refresh", "--json"]));
|
|
assert.equal(
|
|
allRefreshed.find((entry: { id: string }) => entry.id === cold.id).report.windows[0].usedPct,
|
|
3,
|
|
);
|
|
for (const id of ["cli-usage:work", "missing"]) {
|
|
const unknown = await context.paseo(["usage", "inspect", id, "--json"]);
|
|
assert.equal(unknown.exitCode, 1);
|
|
assert.equal(unknown.stdout, "");
|
|
assert.equal(JSON.parse(unknown.stderr).error.code, "REPORT_NOT_FOUND");
|
|
}
|
|
const agentFailure = await context.paseo(["usage", "ls", "--agent", "missing-agent", "--json"]);
|
|
assert.equal(agentFailure.exitCode, 1);
|
|
assert.equal(agentFailure.stdout, "");
|
|
assert.match(JSON.parse(agentFailure.stderr).error.message, /Unknown agent/);
|
|
const remove = await context.paseo(["plugin", "remove", "cli-usage", "--json"]);
|
|
assert.equal(remove.exitCode, 0, remove.stderr);
|
|
assert.equal((await ok(["usage", "ls", "--json"])).trim(), "[]");
|
|
assert.equal((await ok(["usage"])).trim(), "No usage reports returned");
|
|
const connection = await context.paseo(["usage", "ls", "--host", "127.0.0.1:1", "--json"]);
|
|
assert.equal(connection.exitCode, 1);
|
|
assert.equal(connection.stdout, "");
|
|
assert.equal(JSON.parse(connection.stderr).error.code, "DAEMON_UNREACHABLE");
|
|
console.log(
|
|
"Usage CLI: cold inspect, default/ls, complete JSON, mixed statuses, all windows/balances, inspect details, refresh, IDs, errors and empty discovery passed.",
|
|
);
|
|
} finally {
|
|
await context.stop();
|
|
}
|