summaryrefslogtreecommitdiffhomepage
path: root/packages/cli/src/main.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-27 01:12:40 +0900
committerAdam Malczewski <[email protected]>2026-06-27 01:12:40 +0900
commit98b0638838a8e754927d8c030ce8bded18d63e7d (patch)
tree0d4e21c3d4792fcd77e1040373b260e38efa34ce /packages/cli/src/main.ts
parentd92a4af6191d7d20acf861adf605ad0227b6b287 (diff)
parent61e45e60d699ed1ca46f94a8f181c92a940317c6 (diff)
downloaddispatch-98b0638838a8e754927d8c030ce8bded18d63e7d.tar.gz
dispatch-98b0638838a8e754927d8c030ce8bded18d63e7d.zip
Merge branch 'dev' into feature/heartbeat
# Conflicts: # packages/host-bin/package.json # packages/host-bin/src/main.ts # packages/session-orchestrator/src/orchestrator.ts # packages/system-prompt/src/service.test.ts # packages/system-prompt/src/service.ts # packages/system-prompt/src/types.ts # packages/transport-contract/package.json # packages/transport-http/package.json # packages/transport-http/src/app.test.ts # packages/transport-http/src/app.ts # packages/transport-http/src/extension.ts # packages/transport-http/tsconfig.json # tsconfig.json
Diffstat (limited to 'packages/cli/src/main.ts')
-rw-r--r--packages/cli/src/main.ts414
1 files changed, 207 insertions, 207 deletions
diff --git a/packages/cli/src/main.ts b/packages/cli/src/main.ts
index cba0de7..9fca347 100644
--- a/packages/cli/src/main.ts
+++ b/packages/cli/src/main.ts
@@ -9,15 +9,15 @@ import { readFile } from "node:fs/promises";
import { parseArgs } from "./args.js";
import { formatCatalog } from "./catalog.js";
import {
- compactConversation,
- enqueueMessage,
- fetchConversations,
- fetchLastMessage,
- fetchModels,
- openConversation,
- resolveConversationId,
- stopTurn,
- streamChat,
+ compactConversation,
+ enqueueMessage,
+ fetchConversations,
+ fetchLastMessage,
+ fetchModels,
+ openConversation,
+ resolveConversationId,
+ stopTurn,
+ streamChat,
} from "./http.js";
import { buildChatRequest, composeMessage } from "./message.js";
import { extractLastText, formatConversationList, renderEvent } from "./render.js";
@@ -36,214 +36,214 @@ const USAGE = `Usage:
Effort levels: low, medium, high (default), xhigh, max`;
async function main(): Promise<void> {
- const defaultServer = `http://localhost:${process.env.BACKEND_PORT ?? "24203"}`;
- const parsed = parseArgs(process.argv.slice(2), { defaultServer });
+ const defaultServer = `http://localhost:${process.env.BACKEND_PORT ?? "24203"}`;
+ const parsed = parseArgs(process.argv.slice(2), { defaultServer });
- switch (parsed.kind) {
- case "help":
- process.stdout.write(`${USAGE}\n`);
- process.exit(0);
- break;
- case "error":
- process.stderr.write(`Error: ${parsed.message}\n`);
- process.exit(1);
- break;
- case "models": {
- const result = await fetchModels({ fetchImpl: globalThis.fetch }, { server: parsed.server });
- process.stdout.write(`${formatCatalog(result)}\n`);
- 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 }),
- ...(status !== undefined && { status }),
- ...(parsed.workspaceId !== undefined && { workspaceId: parsed.workspaceId }),
- },
- );
- const table = formatConversationList(result.conversations, Date.now());
- if (table.length > 0) process.stdout.write(`${table}\n`);
- break;
- }
- case "read": {
- const resolved = await resolveConversationId(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, shortId: parsed.conversationId },
- );
- if (typeof resolved !== "string") {
- process.stderr.write(`${resolved.error}\n`);
- process.exit(1);
- }
- const last = await fetchLastMessage(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, conversationId: resolved },
- );
- if (last.content.length > 0) process.stdout.write(`${last.content}\n`);
- break;
- }
- case "compact": {
- const resolved = await resolveConversationId(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, shortId: parsed.conversationId },
- );
- if (typeof resolved !== "string") {
- process.stderr.write(`${resolved.error}\n`);
- process.exit(1);
- }
- const result = await compactConversation(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, conversationId: resolved },
- );
- process.stdout.write(
- `Compacted ${resolved}: ${result.messagesSummarized} messages summarized, ${result.messagesKept} kept.\n`,
- );
- break;
- }
- case "stop": {
- const resolved = await resolveConversationId(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, shortId: parsed.conversationId },
- );
- if (typeof resolved !== "string") {
- process.stderr.write(`${resolved.error}\n`);
- process.exit(1);
- }
- const result = await stopTurn(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, conversationId: resolved },
- );
- process.stdout.write(
- result.abortedTurn
- ? `Stopped generation for ${resolved}\n`
- : `No active generation for ${resolved}\n`,
- );
- break;
- }
- case "open": {
- const resolved = await resolveConversationId(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, shortId: parsed.conversationId },
- );
- if (typeof resolved !== "string") {
- process.stderr.write(`${resolved.error}\n`);
- process.exit(1);
- }
- await openConversation(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, conversationId: resolved },
- );
- process.stdout.write(`Signaled frontend to open ${resolved}\n`);
- break;
- }
- case "send": {
- const resolved = await resolveConversationId(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, shortId: parsed.conversationId },
- );
- if (typeof resolved !== "string") {
- process.stderr.write(`${resolved.error}\n`);
- process.exit(1);
- }
- const conversationId = resolved;
+ switch (parsed.kind) {
+ case "help":
+ process.stdout.write(`${USAGE}\n`);
+ process.exit(0);
+ break;
+ case "error":
+ process.stderr.write(`Error: ${parsed.message}\n`);
+ process.exit(1);
+ break;
+ case "models": {
+ const result = await fetchModels({ fetchImpl: globalThis.fetch }, { server: parsed.server });
+ process.stdout.write(`${formatCatalog(result)}\n`);
+ 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 }),
+ ...(status !== undefined && { status }),
+ ...(parsed.workspaceId !== undefined && { workspaceId: parsed.workspaceId }),
+ },
+ );
+ const table = formatConversationList(result.conversations, Date.now());
+ if (table.length > 0) process.stdout.write(`${table}\n`);
+ break;
+ }
+ case "read": {
+ const resolved = await resolveConversationId(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, shortId: parsed.conversationId },
+ );
+ if (typeof resolved !== "string") {
+ process.stderr.write(`${resolved.error}\n`);
+ process.exit(1);
+ }
+ const last = await fetchLastMessage(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, conversationId: resolved },
+ );
+ if (last.content.length > 0) process.stdout.write(`${last.content}\n`);
+ break;
+ }
+ case "compact": {
+ const resolved = await resolveConversationId(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, shortId: parsed.conversationId },
+ );
+ if (typeof resolved !== "string") {
+ process.stderr.write(`${resolved.error}\n`);
+ process.exit(1);
+ }
+ const result = await compactConversation(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, conversationId: resolved },
+ );
+ process.stdout.write(
+ `Compacted ${resolved}: ${result.messagesSummarized} messages summarized, ${result.messagesKept} kept.\n`,
+ );
+ break;
+ }
+ case "stop": {
+ const resolved = await resolveConversationId(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, shortId: parsed.conversationId },
+ );
+ if (typeof resolved !== "string") {
+ process.stderr.write(`${resolved.error}\n`);
+ process.exit(1);
+ }
+ const result = await stopTurn(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, conversationId: resolved },
+ );
+ process.stdout.write(
+ result.abortedTurn
+ ? `Stopped generation for ${resolved}\n`
+ : `No active generation for ${resolved}\n`,
+ );
+ break;
+ }
+ case "open": {
+ const resolved = await resolveConversationId(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, shortId: parsed.conversationId },
+ );
+ if (typeof resolved !== "string") {
+ process.stderr.write(`${resolved.error}\n`);
+ process.exit(1);
+ }
+ await openConversation(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, conversationId: resolved },
+ );
+ process.stdout.write(`Signaled frontend to open ${resolved}\n`);
+ break;
+ }
+ case "send": {
+ const resolved = await resolveConversationId(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, shortId: parsed.conversationId },
+ );
+ if (typeof resolved !== "string") {
+ process.stderr.write(`${resolved.error}\n`);
+ process.exit(1);
+ }
+ const conversationId = resolved;
- if (parsed.open) {
- await openConversation(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, conversationId },
- );
- process.stdout.write(`Signaled frontend to open ${conversationId}\n`);
- }
+ if (parsed.open) {
+ await openConversation(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, conversationId },
+ );
+ process.stdout.write(`Signaled frontend to open ${conversationId}\n`);
+ }
- let fileContent: string | undefined;
- if (parsed.file) {
- fileContent = await readFile(parsed.file, "utf-8");
- }
- const message = composeMessage({
- ...(parsed.text !== undefined && { text: parsed.text }),
- ...(parsed.file !== undefined && { file: parsed.file }),
- ...(fileContent !== undefined && { fileContent }),
- });
+ let fileContent: string | undefined;
+ if (parsed.file) {
+ fileContent = await readFile(parsed.file, "utf-8");
+ }
+ const message = composeMessage({
+ ...(parsed.text !== undefined && { text: parsed.text }),
+ ...(parsed.file !== undefined && { file: parsed.file }),
+ ...(fileContent !== undefined && { fileContent }),
+ });
- if (parsed.queue) {
- const queued = await enqueueMessage(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, conversationId, text: message },
- );
- const line = queued.startedTurn
- ? `Started turn for ${conversationId}`
- : `Queued to ${conversationId}`;
- process.stdout.write(`${line}\n`);
- } else {
- const request = {
- conversationId,
- message,
- ...(parsed.cwd !== undefined && { cwd: parsed.cwd }),
- ...(parsed.reasoningEffort !== undefined && { reasoningEffort: parsed.reasoningEffort }),
- ...(parsed.workspaceId !== undefined && { workspaceId: parsed.workspaceId }),
- };
- const { events } = await streamChat(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, request },
- );
- const collected = [];
- for await (const event of events) {
- if (event.type === "error") {
- process.stderr.write(`${event.message}\n`);
- process.exit(1);
- }
- collected.push(event);
- if (event.type === "done") break;
- }
- process.stdout.write(`${extractLastText(collected)}\n`);
- process.stdout.write(`[conversation] ${conversationId}\n`);
- }
- break;
- }
- case "chat": {
- let fileContent: string | undefined;
- if (parsed.file) {
- fileContent = await readFile(parsed.file, "utf-8");
- }
+ if (parsed.queue) {
+ const queued = await enqueueMessage(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, conversationId, text: message },
+ );
+ const line = queued.startedTurn
+ ? `Started turn for ${conversationId}`
+ : `Queued to ${conversationId}`;
+ process.stdout.write(`${line}\n`);
+ } else {
+ const request = {
+ conversationId,
+ message,
+ ...(parsed.cwd !== undefined && { cwd: parsed.cwd }),
+ ...(parsed.reasoningEffort !== undefined && { reasoningEffort: parsed.reasoningEffort }),
+ ...(parsed.workspaceId !== undefined && { workspaceId: parsed.workspaceId }),
+ };
+ const { events } = await streamChat(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, request },
+ );
+ const collected = [];
+ for await (const event of events) {
+ if (event.type === "error") {
+ process.stderr.write(`${event.message}\n`);
+ process.exit(1);
+ }
+ collected.push(event);
+ if (event.type === "done") break;
+ }
+ process.stdout.write(`${extractLastText(collected)}\n`);
+ process.stdout.write(`[conversation] ${conversationId}\n`);
+ }
+ break;
+ }
+ case "chat": {
+ let fileContent: string | undefined;
+ if (parsed.file) {
+ fileContent = await readFile(parsed.file, "utf-8");
+ }
- const cwd = parsed.cwd ?? process.cwd();
- const message = composeMessage({
- ...(parsed.text !== undefined && { text: parsed.text }),
- ...(parsed.file !== undefined && { file: parsed.file }),
- ...(fileContent !== undefined && { fileContent }),
- });
- const request = buildChatRequest(parsed, { cwd, message });
+ const cwd = parsed.cwd ?? process.cwd();
+ const message = composeMessage({
+ ...(parsed.text !== undefined && { text: parsed.text }),
+ ...(parsed.file !== undefined && { file: parsed.file }),
+ ...(fileContent !== undefined && { fileContent }),
+ });
+ const request = buildChatRequest(parsed, { cwd, message });
- const { conversationId, events } = await streamChat(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, request },
- );
+ const { conversationId, events } = await streamChat(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, request },
+ );
- if (conversationId && parsed.open) {
- await openConversation(
- { fetchImpl: globalThis.fetch },
- { server: parsed.server, conversationId },
- );
- process.stdout.write(`Signaled frontend to open ${conversationId}\n`);
- }
+ if (conversationId && parsed.open) {
+ await openConversation(
+ { fetchImpl: globalThis.fetch },
+ { server: parsed.server, conversationId },
+ );
+ process.stdout.write(`Signaled frontend to open ${conversationId}\n`);
+ }
- for await (const event of events) {
- const rendered = renderEvent(event, { showReasoning: parsed.showReasoning });
- if (rendered?.stdout) process.stdout.write(rendered.stdout);
- if (rendered?.stderr) process.stderr.write(rendered.stderr);
- }
+ for await (const event of events) {
+ const rendered = renderEvent(event, { showReasoning: parsed.showReasoning });
+ if (rendered?.stdout) process.stdout.write(rendered.stdout);
+ if (rendered?.stderr) process.stderr.write(rendered.stderr);
+ }
- if (conversationId) {
- process.stdout.write(`\n[conversation] ${conversationId}\n`);
- }
- break;
- }
- }
+ if (conversationId) {
+ process.stdout.write(`\n[conversation] ${conversationId}\n`);
+ }
+ break;
+ }
+ }
}
main().catch((err: unknown) => {
- process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}\n`);
- process.exit(1);
+ process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}\n`);
+ process.exit(1);
});