feat(S-201): Define job types and storage interfaces

This commit is contained in:
2026-05-19 19:58:48 -05:00
parent 21c13562a7
commit abf7726071
2 changed files with 54 additions and 12 deletions
+1 -12
View File
@@ -1,8 +1,6 @@
import type { ChildProcess } from "node:child_process";
import { spawn as defaultSpawn } from "node:child_process"; import { spawn as defaultSpawn } from "node:child_process";
import type { PathLike } from "node:fs";
import { existsSync as defaultExistsSync } from "node:fs"; import { existsSync as defaultExistsSync } from "node:fs";
import type { ClientName, ExecResult, DebugInfo } from "./types.js"; import type { ClientName, ExecResult, DebugInfo, ExecuteOptions } from "./types.js";
import { ClientNotFoundError, ExecError } from "./types.js"; import { ClientNotFoundError, ExecError } from "./types.js";
const CLIENT_ARGS: Record<ClientName, (prompt: string) => string[]> = { const CLIENT_ARGS: Record<ClientName, (prompt: string) => string[]> = {
@@ -11,15 +9,6 @@ const CLIENT_ARGS: Record<ClientName, (prompt: string) => string[]> = {
opencode: (p) => ["run", "--dangerously-skip-permissions", p], opencode: (p) => ["run", "--dangerously-skip-permissions", p],
}; };
export interface ExecuteOptions {
clientPath?: string;
timeoutMs?: number;
debug?: boolean;
onDebug?: (info: DebugInfo) => void;
spawn?: (command: string, args: string[], options?: { shell?: boolean }) => ChildProcess;
existsSync?: (path: PathLike) => boolean;
}
export async function executePrompt( export async function executePrompt(
client: ClientName, client: ClientName,
prompt: string, prompt: string,
+53
View File
@@ -1,3 +1,6 @@
import type { ChildProcess } from "node:child_process";
import type { PathLike } from "node:fs";
export type ClientName = "codex" | "claude" | "opencode"; export type ClientName = "codex" | "claude" | "opencode";
export interface ClientInfo { export interface ClientInfo {
@@ -27,6 +30,42 @@ export interface DebugInfo {
noisySuccess: boolean; noisySuccess: boolean;
} }
export interface ExecuteOptions {
clientPath?: string;
timeoutMs?: number;
debug?: boolean;
onDebug?: (info: DebugInfo) => void;
spawn?: (command: string, args: string[], options?: { shell?: boolean }) => ChildProcess;
existsSync?: (path: PathLike) => boolean;
}
export type JobStatus = "running" | "completed" | "failed" | "timed_out" | "cancelled";
export interface Job {
id: string;
client: ClientName;
prompt: string;
status: JobStatus;
result?: ExecResult;
error?: string;
startedAt: string;
completedAt?: string;
pid?: number;
}
/**
* On-disk storage contract for job files under
* ~/.openclaw/ai-cli-dispatch/jobs/<jobId>.json
*/
export interface JobRecord extends Job {
stdout: string;
stderr: string;
}
export interface JobStartOptions extends ExecuteOptions {
jobDir?: string;
}
export class ClientNotFoundError extends Error { export class ClientNotFoundError extends Error {
constructor(client: string) { constructor(client: string) {
super(`Client "${client}" not found or not installed.`); super(`Client "${client}" not found or not installed.`);
@@ -43,3 +82,17 @@ export class ExecError extends Error {
this.result = result; this.result = result;
} }
} }
export class JobNotFoundError extends Error {
constructor(jobId: string) {
super(`Job "${jobId}" not found.`);
this.name = "JobNotFoundError";
}
}
export class JobResultUnavailableError extends Error {
constructor(jobId: string, status: JobStatus) {
super(`Job "${jobId}" result is not available (status: ${status}).`);
this.name = "JobResultUnavailableError";
}
}