summaryrefslogtreecommitdiffhomepage
path: root/packages/cli
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cli')
-rw-r--r--packages/cli/src/args.test.ts29
-rw-r--r--packages/cli/src/args.ts23
-rw-r--r--packages/cli/src/http.test.ts23
-rw-r--r--packages/cli/src/http.ts10
-rw-r--r--packages/cli/src/main.ts9
-rw-r--r--packages/cli/src/render.test.ts1
6 files changed, 83 insertions, 12 deletions
diff --git a/packages/cli/src/args.test.ts b/packages/cli/src/args.test.ts
index 62bcafd..992d09f 100644
--- a/packages/cli/src/args.test.ts
+++ b/packages/cli/src/args.test.ts
@@ -190,6 +190,7 @@ describe("parseArgs", () => {
expect(parseArgs(["list"], { defaultServer })).toEqual({
kind: "list",
server: "http://localhost:24203",
+ all: false,
});
});
@@ -198,6 +199,7 @@ describe("parseArgs", () => {
kind: "list",
server: "http://localhost:24203",
query: "abc12345",
+ all: false,
});
});
@@ -206,9 +208,36 @@ describe("parseArgs", () => {
kind: "list",
server: "http://s",
query: "abc",
+ all: false,
});
});
+ it("parses 'list' with --status", () => {
+ expect(parseArgs(["list", "--status", "closed"], { defaultServer })).toEqual({
+ kind: "list",
+ server: "http://localhost:24203",
+ status: "closed",
+ all: false,
+ });
+ });
+
+ it("parses 'list' with --all", () => {
+ expect(parseArgs(["list", "--all"], { defaultServer })).toEqual({
+ kind: "list",
+ server: "http://localhost:24203",
+ all: true,
+ });
+ });
+
+ it("parses 'list' with --status and --all ( --all takes precedence)", () => {
+ const result = parseArgs(["list", "--status", "active", "--all"], { defaultServer });
+ expect(result.kind).toBe("list");
+ if (result.kind === "list") {
+ expect(result.all).toBe(true);
+ expect(result.status).toBe("active");
+ }
+ });
+
it("errors on a second positional argument", () => {
const result = parseArgs(["list", "abc", "def"], { defaultServer });
expect(result.kind).toBe("error");
diff --git a/packages/cli/src/args.ts b/packages/cli/src/args.ts
index d4ed0e9..30fa309 100644
--- a/packages/cli/src/args.ts
+++ b/packages/cli/src/args.ts
@@ -27,7 +27,13 @@ export type ParsedCommand =
readonly showReasoning: boolean;
readonly open: boolean;
}
- | { readonly kind: "list"; readonly server: string; readonly query?: string }
+ | {
+ readonly kind: "list";
+ readonly server: string;
+ readonly query?: string;
+ readonly status?: string;
+ readonly all: boolean;
+ }
| { readonly kind: "open"; readonly server: string; readonly conversationId: string }
| { readonly kind: "read"; readonly server: string; readonly conversationId: string }
| {
@@ -73,11 +79,18 @@ export function parseArgs(argv: readonly string[], opts: ParseOpts): ParsedComma
if (first === "list") {
let server = opts.defaultServer;
let query: string | undefined;
+ let status: string | undefined;
+ let all = false;
for (let i = 1; i < argv.length; i++) {
const arg = argv[i] as string;
if (arg === "--server") {
if (i + 1 >= argv.length) return { kind: "error", message: "--server requires a value" };
server = argv[++i] as string;
+ } else if (arg === "--status") {
+ if (i + 1 >= argv.length) return { kind: "error", message: "--status requires a value" };
+ status = argv[++i];
+ } else if (arg === "--all") {
+ all = true;
} else if (arg.startsWith("--")) {
return { kind: "error", message: `Unknown flag: ${arg}` };
} else if (query !== undefined) {
@@ -86,7 +99,13 @@ export function parseArgs(argv: readonly string[], opts: ParseOpts): ParsedComma
query = arg;
}
}
- return { kind: "list", server, ...(query !== undefined && { query }) };
+ return {
+ kind: "list",
+ server,
+ ...(query !== undefined && { query }),
+ ...(status !== undefined && { status }),
+ all,
+ };
}
if (first === "read") {
diff --git a/packages/cli/src/http.test.ts b/packages/cli/src/http.test.ts
index 013492e..3e7befe 100644
--- a/packages/cli/src/http.test.ts
+++ b/packages/cli/src/http.test.ts
@@ -251,7 +251,9 @@ describe("fetchConversations", () => {
it("requests GET /conversations with no query when query omitted", async () => {
let calledUrl: string | undefined;
const list: ConversationListResponse = {
- conversations: [{ id: "abcdef1234567890", title: "first", createdAt: 1, lastActivityAt: 2 }],
+ conversations: [
+ { id: "abcdef1234567890", title: "first", createdAt: 1, lastActivityAt: 2, status: "idle" },
+ ],
};
const fakeFetch = (async (url: string | URL | Request): Promise<Response> => {
calledUrl = String(url);
@@ -277,7 +279,7 @@ describe("fetchConversations", () => {
{ fetchImpl: fakeFetch },
{ server: "http://localhost:24203", query: "abc def" },
);
- expect(calledUrl).toBe("http://localhost:24203/conversations?q=abc%20def");
+ expect(calledUrl).toBe("http://localhost:24203/conversations?q=abc+def");
});
it("throws on non-OK status", async () => {
@@ -400,7 +402,13 @@ describe("resolveConversationId", () => {
it("returns the full id on a single match", async () => {
const fetchImpl = listFetch({
conversations: [
- { id: "abcdef1234567890abcdef1234567890", title: "only", createdAt: 1, lastActivityAt: 2 },
+ {
+ id: "abcdef1234567890abcdef1234567890",
+ title: "only",
+ createdAt: 1,
+ lastActivityAt: 2,
+ status: "idle",
+ },
],
});
const result = await resolveConversationId(
@@ -426,12 +434,19 @@ describe("resolveConversationId", () => {
it("returns an error object listing matches on multiple matches", async () => {
const fetchImpl = listFetch({
conversations: [
- { id: "abcdef1234567890aaaaaaaaaaaaaaaa", title: "first", createdAt: 1, lastActivityAt: 2 },
+ {
+ id: "abcdef1234567890aaaaaaaaaaaaaaaa",
+ title: "first",
+ createdAt: 1,
+ lastActivityAt: 2,
+ status: "idle",
+ },
{
id: "abcdef1234567890bbbbbbbbbbbbbbbb",
title: "second",
createdAt: 1,
lastActivityAt: 3,
+ status: "idle",
},
],
});
diff --git a/packages/cli/src/http.ts b/packages/cli/src/http.ts
index 8434519..876f570 100644
--- a/packages/cli/src/http.ts
+++ b/packages/cli/src/http.ts
@@ -96,16 +96,18 @@ export async function fetchModels(deps: FetchDeps, opts: FetchModelsOpts): Promi
interface FetchConversationsOpts {
readonly server: string;
readonly query?: string;
+ readonly status?: string;
}
export async function fetchConversations(
deps: FetchDeps,
opts: FetchConversationsOpts,
): Promise<ConversationListResponse> {
- const url =
- opts.query !== undefined
- ? `${opts.server}/conversations?q=${encodeURIComponent(opts.query)}`
- : `${opts.server}/conversations`;
+ const params = new URLSearchParams();
+ if (opts.query !== undefined) params.set("q", opts.query);
+ if (opts.status !== undefined) params.set("status", opts.status);
+ const qs = params.toString();
+ const url = qs.length > 0 ? `${opts.server}/conversations?${qs}` : `${opts.server}/conversations`;
const res = await deps.fetchImpl(url);
if (!res.ok) {
diff --git a/packages/cli/src/main.ts b/packages/cli/src/main.ts
index 6df6e23..e709f21 100644
--- a/packages/cli/src/main.ts
+++ b/packages/cli/src/main.ts
@@ -22,7 +22,7 @@ import { extractLastText, formatConversationList, renderEvent } from "./render.j
const USAGE = `Usage:
dispatch models [--server <url>]
- dispatch list [<prefix>] [--server <url>]
+ dispatch list [<prefix>] [--status <active|idle|closed>] [--all] [--server <url>]
dispatch read <conversationId> [--server <url>]
dispatch open <conversationId> [--server <url>]
dispatch send <conversationId> --text "..." [--queue] [--open] [--cwd <dir>] [--effort <level>] [--server <url>]
@@ -50,9 +50,14 @@ async function main(): Promise<void> {
break;
}
case "list": {
+ const status = parsed.all ? undefined : (parsed.status ?? "active,idle");
const result = await fetchConversations(
{ fetchImpl: globalThis.fetch },
- { server: parsed.server, ...(parsed.query !== undefined && { query: parsed.query }) },
+ {
+ server: parsed.server,
+ ...(parsed.query !== undefined && { query: parsed.query }),
+ ...(status !== undefined && { status }),
+ },
);
const table = formatConversationList(result.conversations, Date.now());
if (table.length > 0) process.stdout.write(`${table}\n`);
diff --git a/packages/cli/src/render.test.ts b/packages/cli/src/render.test.ts
index 849d33a..eb89300 100644
--- a/packages/cli/src/render.test.ts
+++ b/packages/cli/src/render.test.ts
@@ -229,6 +229,7 @@ describe("formatConversationList", () => {
title,
createdAt: now - ageMs - 1000,
lastActivityAt: now - ageMs,
+ status: "idle",
});
it("returns empty string for an empty list", () => {