@blundergoat/goat-flow
Version:
AI coding agent harness and local dashboard for Claude Code, OpenAI Codex, Google Antigravity, and GitHub Copilot - setup audits, guardrails, structured skills, deny hooks, and persistent learning loops.
133 lines • 5.31 kB
TypeScript
/**
* Runtime decoders for server-boundary payloads.
*
* Every ingress boundary (HTTP body, WebSocket message) validates payload shape
* before dispatching. These decoders return typed `{ ok: false, error, path }`
* failures so routes can report the exact rejected field instead of letting
* arbitrary shapes fail later in terminal or quality logic.
*
* Deliberately pure TS with no new runtime deps (zod, valibot, etc.) per
* goat-flow's zero-new-dep policy. Narrow shapes are easy enough to validate
* by hand.
*/
import type { AgentId } from "../types.js";
import type { ClientMessage, Runner } from "./types.js";
type DecodeResult<T> = {
ok: true;
value: T;
} | {
ok: false;
error: string;
path: string;
};
/** Terminal-create payload after optional text fields and runner selection are normalised. */
interface TerminalCreateBody {
prompt: string;
projectPath: string;
targetPath: string;
runner: Runner;
}
/** Dashboard project-list state after omitted optional collections use their state-file fallbacks. */
interface ProjectsListBody {
paths: string[];
favorites: string[];
projectTitles: Record<string, string>;
}
/** Dashboard project-path payload for single-project write actions. */
interface ProjectPathBody {
path: string;
}
/** Base64 upload item after structural validation; file safety checks run in the upload handler. */
interface TerminalUploadFile {
name: string;
data: string;
}
/** Terminal upload payload grouped by request so count limits can be enforced before decoding files. */
interface TerminalUploadBody {
files: TerminalUploadFile[];
}
/** Quality-evaluate payload, accepting one pasted document or one bounded file bundle. */
export interface EvaluateBody {
/** Either a single content string (paste / textarea) OR an array of named
* files (multi-file drop). Exactly one must be set. */
content?: string;
files?: {
name: string;
content: string;
}[];
/** Optional filename or display name; used as the analyzed artifact name. */
suggestedName?: string | undefined;
/** Optional explicit kind override; otherwise inferred from frontmatter. */
kind?: "skill" | "shared-reference" | undefined;
}
/** Hook-toggle payload accepted by POST /api/hooks/:hookId/toggle. */
type HookToggleBody = Record<"enabled", boolean>;
/**
* Decode POST /api/terminal/create without defaulting invalid runner names.
*
* @param body Raw request body.
* @param options Runner allow-list plus the fallback used only when `runner` is absent.
* @returns Typed terminal-create payload or a path-specific decoder error.
*/
export declare function decodeTerminalCreateBody(body: string, options: {
validRunners: ReadonlySet<string>;
defaultRunner: AgentId;
}): DecodeResult<TerminalCreateBody>;
/**
* Decode POST /api/projects/list while preserving dashboard state-file fallbacks.
*
* @param body Raw request body.
* @returns Typed project-list payload or a path-specific decoder error.
*/
export declare function decodeProjectsListBody(body: string): DecodeResult<ProjectsListBody>;
/**
* Decode a body carrying the target project path for a dashboard write action.
*
* @param body Raw request body.
* @returns Typed project-path payload or a path-specific decoder error.
*/
export declare function decodeProjectPathBody(body: string): DecodeResult<ProjectPathBody>;
/**
* Decode POST /api/hooks/:hookId/toggle.
*
* @param body - raw JSON request body from the dashboard route
* @returns decoded hook toggle payload or a field-specific validation error
*/
export declare function decodeHookToggleBody(body: string): DecodeResult<HookToggleBody>;
/**
* Decode POST /api/terminal/:id/upload-image before content safety checks.
*
* The handler enforces MIME and byte limits after this structural pass; this
* decoder only proves the request has named base64 entries and a valid count.
*
* @param body Raw request body.
* @param options Request-level upload limits from the route.
* @returns Typed upload payload or a path-specific decoder error.
*/
export declare function decodeTerminalUploadBody(body: string, options: {
maxFiles: number;
}): DecodeResult<TerminalUploadBody>;
/**
* Decode a terminal WebSocket frame with one branch per supported message type.
*
* The socket handler sends these errors back to the client, so the explicit
* input and resize branches intentionally preserve the exact rejected field.
*
* @param raw Raw WebSocket frame text.
* @returns Typed client message or a path-specific decoder error.
*/
export declare function decodeClientMessage(raw: string): DecodeResult<ClientMessage>;
export declare const MAX_EVALUATE_CONTENT_BYTES: number;
/**
* Decode and validate a `POST /api/quality/evaluate` request body.
*
* This stays explicit because the route accepts the current multi-file uploader
* and the older single-text form; ambiguous bodies are rejected before quality
* scoring. The deprecated `/api/quality/analyse` alias reuses the same shape.
*
* @param body Raw request body.
* @returns Typed evaluate payload or a path-specific decoder error.
*/
export declare function decodeEvaluateBody(body: string): DecodeResult<EvaluateBody>;
export {};
//# sourceMappingURL=decoders.d.ts.map