Files
paseo/packages/cli/src/commands/chat/shared.ts
T
Mohamed Boudra be41911083 feat: add loop, schedule, and chat CLI commands (#149)
* Add metrics collection and terminal performance tests

* feat: add loop, schedule, and chat commands with slash-namespaced RPC

Introduce three new server-side features with CLI command groups:

- `paseo loop` — iterative agent execution with verify-check/verify-prompt
- `paseo schedule` — recurring tasks on interval or cron cadence
- `paseo chat` — chat rooms for agent-to-agent coordination

All features use new slash-namespaced RPC methods (e.g. `loop/run`,
`schedule/create`, `chat/post`) instead of flat message types, backed
by file-based persistence and wired through the existing WebSocket
session dispatch.

* test: stabilize loop schedule chat rollout
2026-03-28 00:25:04 +07:00

85 lines
2.4 KiB
TypeScript

import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
import { parseDuration } from "../../utils/duration.js";
import type { CommandError, CommandOptions } from "../../output/index.js";
export interface ChatCommandOptions extends CommandOptions {
host?: string;
}
export async function connectChatClient(host?: string) {
const daemonHost = getDaemonHost({ host });
try {
const client = await connectToDaemon({ host });
return { client, daemonHost };
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
const error: CommandError = {
code: "DAEMON_NOT_RUNNING",
message: `Cannot connect to daemon at ${daemonHost}: ${message}`,
details: "Start the daemon with: paseo daemon start",
};
throw error;
}
}
export function toChatCommandError(code: string, action: string, err: unknown): CommandError {
if (err && typeof err === "object" && "code" in err && "message" in err) {
return err as CommandError;
}
const message = err instanceof Error ? err.message : String(err);
const rpcCode =
typeof err === "object" && err !== null && "code" in err && typeof err.code === "string"
? err.code
: undefined;
return {
code: rpcCode ?? code,
message: `Failed to ${action}: ${message}`,
};
}
export function parseSinceValue(input?: string): string | undefined {
if (!input) {
return undefined;
}
try {
const durationMs = parseDuration(input);
return new Date(Date.now() - durationMs).toISOString();
} catch {
const timestamp = new Date(input);
if (Number.isNaN(timestamp.getTime())) {
const error: CommandError = {
code: "INVALID_SINCE",
message: "Invalid --since value",
details: "Use a duration like 10m or an ISO timestamp.",
};
throw error;
}
return timestamp.toISOString();
}
}
export function parseTimeoutMs(input?: string): number | undefined {
if (!input) {
return undefined;
}
try {
const timeoutMs = parseDuration(input);
if (timeoutMs <= 0) {
throw new Error("Timeout must be positive");
}
return timeoutMs;
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
const error: CommandError = {
code: "INVALID_TIMEOUT",
message: "Invalid timeout value",
details: message,
};
throw error;
}
}