File size: 5,232 Bytes
bc575bc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | import { describe, expect, test } from "vitest";
import { cli } from "../src/cli/experimental/cli.ts";
const UNSUPPORTED_SERVER_OPTIONS = "The experimental server command does not support existing CLI options yet";
const UNSUPPORTED_CLIENT_OPTIONS = "The experimental client command does not support existing CLI options yet";
describe("experimental CLI commands", () => {
test("parses server configuration", () => {
expect(
cli.parse([
"server",
"--server-id",
"00000000-0000-4000-8000-000000000001",
"--session-dir",
"~/pi-sessions",
"--provider",
"anthropic",
"--model",
"claude-sonnet-4-5",
"-e",
"./first-plugin",
"-e=./second-plugin",
]),
).toEqual({
ok: true,
command: {
command: "server",
serverId: "00000000-0000-4000-8000-000000000001",
sessionDir: "~/pi-sessions",
provider: "anthropic",
model: "claude-sonnet-4-5",
pluginPackages: ["./first-plugin", "./second-plugin"],
},
});
});
test("parses provider-qualified server models", () => {
expect(cli.parse(["server", "--model", "anthropic/claude-sonnet-4-5:high"])).toEqual({
ok: true,
command: { command: "server", model: "anthropic/claude-sonnet-4-5:high" },
});
});
test("parses client transport addresses", () => {
expect(cli.parse(["client", "--connect", "unix:///tmp/pi.sock"])).toEqual({
ok: true,
command: { command: "client", connect: { transport: "unix", path: "/tmp/pi.sock" } },
});
expect(
cli.parse(["client", "--connect", "radius://00000000-0000-4000-8000-000000000001", "--session-id", "demo-1"]),
).toEqual({
ok: true,
command: {
command: "client",
connect: { transport: "radius", serverId: "00000000-0000-4000-8000-000000000001" },
sessionId: "demo-1",
},
});
});
test.each([
["-c", "continue"],
["--continue", "continue"],
["-r", "resume"],
["--resume", "resume"],
] as const)("parses client Session selection %s", (option, property) => {
expect(cli.parse(["client", option])).toEqual({
ok: true,
command: { command: "client", [property]: true },
});
});
test("parses a Session selection followed by a one-shot prompt", () => {
expect(cli.parse(["client", "-r", "Explain this project"])).toEqual({
ok: true,
command: { command: "client", resume: true, prompt: "Explain this project" },
});
});
test("parses client model and plugin configuration", () => {
expect(
cli.parse([
"client",
"--model",
"anthropic/claude-sonnet-4-5:high",
"-e",
"./first-plugin",
"-e",
"./second-plugin",
]),
).toEqual({
ok: true,
command: {
command: "client",
model: "anthropic/claude-sonnet-4-5:high",
pluginPackages: ["./first-plugin", "./second-plugin"],
},
});
});
test.each([
[["--auth-token", "secret"], { type: "token", token: "secret" }],
[["--auth-token-file", "/tmp/token"], { type: "file", path: "/tmp/token" }],
] as const)("parses authentication source %j", (argv, auth) => {
for (const command of ["server", "client"] as const) {
expect(cli.parse([command, ...argv])).toMatchObject({ ok: true, command: { command, auth } });
}
});
test.each(["server", "client"] as const)("permits omitted authentication for %s", (command) => {
expect(cli.parse([command])).toEqual({ ok: true, command: { command } });
});
test.each([
[["client", "--listen", "unix:///tmp/pi.sock"], UNSUPPORTED_CLIENT_OPTIONS],
[["server", "--listen", "unix:///tmp/pi.sock"], UNSUPPORTED_SERVER_OPTIONS],
[["server", "--connect", "unix:///tmp/pi.sock"], UNSUPPORTED_SERVER_OPTIONS],
[["client", "--connect", "ws://localhost:8080"], 'Unsupported --connect transport "ws:"'],
[["client", "--connect", "radius://not-a-server"], "Radius transport address requires"],
[["client", "--connect", "unix://relative.sock"], "Unix transport address must not include an authority"],
[["client", "--connect", "unix:///tmp/pi.sock?wrong=value"], "Invalid --connect address"],
[["client", "--provider", "anthropic"], "--provider requires --model"],
[["client", "-c", "-r"], "--session-id, --continue, and --resume are mutually exclusive"],
[["client", "--continue=true"], "--continue does not take a value"],
[["server", "--provider", "anthropic"], "--provider requires --model"],
[["server", "--server-id", "not-a-uuid"], "Invalid --server-id"],
[["server", "--server-id"], "--server-id requires a value"],
[["server", "--session-dir"], "--session-dir requires a value"],
[["client", "-e"], "-e requires a value"],
[
["server", "--session-dir", "/tmp/first", "--session-dir=/tmp/second"],
"--session-dir may only be specified once",
],
[["client", "--connect="], "--connect requires a value"],
] as const)("rejects invalid experimental input %j", (argv, error) => {
const result = cli.parse(argv);
expect(result).toMatchObject({ ok: false });
if (!result.ok) expect(result.errors).toContainEqual(expect.stringContaining(error));
});
test("rejects unsupported options without parsing them through the stable CLI", () => {
expect(cli.parse(["client", "--tui-mode", "wrong", "--model", "claude-sonnet"])).toEqual({
ok: false,
errors: [UNSUPPORTED_CLIENT_OPTIONS],
});
});
});
|