/** * @fileoverview Types shared across the task-show plugin. * * The plugin keeps its own model of what constitutes a "task solving trace" * (a sequence of tool calls with metadata) and exposes helpers used by both * the data collector, the HTTP server, and the visualization frontend. */ /** * A single tool invocation captured by the `tool:after.execute` hook. * * Fields mirror the payload the global hook manager emits: * { tool: { name, ... }, args, context, result } * plus a few derived fields (timestamp, durationMs, sequence) that make the * frontend rendering straightforward. */ export interface ToolCallRecord { /** Zero-based sequence number within the task. */ sequence: number; /** Name of the tool that was invoked (e.g. `read_file`, `bash`). */ toolName: string; /** Arbitrary JSON-serializable arguments that were passed to the tool. */ args: Record; /** Whether the tool reported success. */ success: boolean; /** Truncated output text. We intentionally do not store the entire result body. */ outputPreview: string; /** Error message (if the tool failed). */ error?: string; /** Execution duration in milliseconds. */ durationMs: number; /** Unix ms when the call finished. */ timestamp: number; /** Iteration index within the agent loop (if exposed by the hook context). */ iteration?: number; /** Optional metadata bag carried over from the tool result. */ metadata?: Record; /** If the input args look like image-related content, we tag the call so the UI can render a badge. */ hasAttachment?: boolean; } /** * A complete task session — the visualization root. */ export interface TaskSession { /** Task ID as exposed by the TaskComponent / getCurrentTaskId(). */ taskId: number; /** Human-readable title (best-effort, often empty for very short tasks). */ title: string; /** Session start time. */ startedAt: number; /** Session end time (set when the task transitions to a terminal status). */ endedAt?: number; /** Current lifecycle status. */ status: "running" | "completed" | "failed" | "cancelled" | "paused" | "unknown"; /** Ordered list of tool calls. */ toolCalls: ToolCallRecord[]; /** Cached URL the visualization page is served at. */ visualizationUrl?: string; /** * v2.3.0+: Bag of host-supplied context for the task. The host * (e.g. `task:before.create` / `task:after.create` payloads) may * carry metadata about where the task is running, what worktree * it was launched in, etc. Today the file-tree sidebar is the * only consumer — `context.worktree` scopes `git ls-files` to the * task's working directory. * * Optional: hosts that don't supply this field keep the v2.2.x * behaviour (file tree = `process.cwd()`). */ context?: { /** * Absolute path to the git worktree / repo root the task is * running in. When set, the file-tree sidebar and the * `/api/task/:id/file-tree` endpoint scope `git ls-files` to * this path. When missing / empty, the plugin falls back to * `process.cwd()` (backward compatible). */ worktree?: string; /** * Allow other host-supplied keys without breaking the type. * We don't model them yet — but future consumers (branch, base * commit, role) can land here without breaking existing hosts. */ [key: string]: unknown; }; } /** * Minimal PluginEnv surface we depend on. * * We avoid importing private types from the host project's barrels so the * plugin stays loosely coupled. Tests can substitute a fake. */ export interface PluginEnvLike { registerHook?: (def: { point: string; priority?: number; name?: string; handler: (ctx: unknown) => unknown | Promise; }) => void; getComponent?: (name: string) => unknown; getConfig?: (key: string) => unknown; } /** * Configuration consumed by the plugin. * * Mirrors the schema described in plugin.json (which is what the loader passes * through `config`). */ export interface TaskShowConfig { port: number; host: string; autoStart: boolean; maxStoredTasks: number; publicDir: string; /** Custom client-side logger prefix (handy for tests). */ logPrefix?: string; /** * v0.6.9+: Directories the "/api/file-content" endpoint will allow reading * files from. Defaults to cwd + $HOME. Files outside these paths are * rejected with 403. Add additional trusted roots (e.g. /tmp/test-fixtures) * to allow your dev/test fixtures to be previewed. Use with care. */ fileSandboxPaths?: string[]; /** * v0.7.0+: Absolute path to the `roy-agent` executable used by the * "Task lifecycle pipeline" feature. Default is `/packages/cli/dist/bin/roy-agent.js` * (the local CLI build). Tests typically override this with a mock runner. */ royAgentCliPath?: string; /** v0.7.0+: How long (ms) to cache parsed CLI envelopes. Default 5000. */ operationsCacheTtlMs?: number; /** v0.7.0+: Hard cap on operations returned per task (newest first). Default 200. */ maxOperations?: number; /** v0.7.0+: Maximum characters kept per description. Default 2000. */ maxDescriptionChars?: number; /** v0.7.0+: Wall-clock timeout for the CLI spawn. Default 5000 ms. */ cliTimeoutMs?: number; /** v0.7.0+: Maximum stdout bytes accepted from the CLI. Default 1 MiB. */ cliMaxBytes?: number; /** * v0.8.10+: Hard cap on the operations cache (one entry per task id). * Older stale entries are dropped first when the cap is exceeded. * Default 256. */ operationsCacheMaxEntries?: number; /** * v0.8.10+: Hard cap on the tasks-tree cache (one entry per unique * filter combination). Default 64. */ tasksTreeCacheMaxEntries?: number; /** * v0.8.10+: Grace period for `tool:before.execute` entries that never * receive a matching `tool:after.execute` (e.g. crashed tool, host * bug). Entries older than this are swept on the next `before` hook * call. Default 60_000 ms (1 minute). Set to 0 to disable. */ pendingStartTtlMs?: number; /** * v0.8.10+: FIFO cap on the `finalizedTaskIds` dedup set so it cannot * grow unbounded in long-lived hosts. Default 4096. */ maxFinalizedTaskIds?: number; } /** * Default configuration. Keeping these as a single source of truth simplifies * the loader in plugin.json. * * v0.5.0+: SSE replaces the previous `env.notify` mechanism. URL injection * is no longer supported — visualization reach-out is via the SSE event * stream broadcast by the local HTTP service. * * v0.8.10+: Heap-bounded defaults (Task #2537). `pendingStartTtlMs`, * `operationsCacheMaxEntries`, `tasksTreeCacheMaxEntries`, and * `maxFinalizedTaskIds` keep the plugin's in-memory Maps and Sets * bounded so a long-lived CLI session cannot OOM at 4 GiB V8 heap. */ export declare const DEFAULT_CONFIG: TaskShowConfig; /** * Type of events broadcast over the SSE channel. * * - `task.created` — a new task session has been opened (task:after.create * hook fired). Payload is the full session snapshot. * - `task.updated` — the session's status / title / progress changed * (task:after.update with a non-terminal status). Payload is the session. * - `task.completed` — the task transitioned to a terminal status * (task:after.complete). Payload is the finalized session. * - `tool.recorded` — a single tool call was appended to the session * (tool:after.execute). Payload is the updated session plus the new * ToolCallRecord for incremental UI updates. * - `tool.called` — v1.1.0+ alias for `tool.recorded` matching the * 3-class event contract (task.created / operation.updated / tool.called). * Same payload shape; existing `tool.recorded` listeners continue to work. * - `operation.updated` — v1.1.0+ the operations timeline changed for a task * (cache refresh on `/api/tasks/:id/operations`). Payload is the full * TaskOperationsEnvelope so the client can patch the pipeline DOM in place. * * Events are JSON-encoded and delivered as standard SSE `data:` frames. */ export type TaskEventType = "task.created" | "task.updated" | "task.completed" | "tool.recorded" | "tool.called" | "operation.updated"; /** * A single event broadcast to all SSE subscribers. * * `payload` is intentionally `unknown` so consumers can branch on `type` * and assert the exact shape they expect. The frontend uses a discriminated * union for type safety. */ export interface TaskEvent { /** Event type discriminator. */ type: TaskEventType; /** Task id the event refers to (always present). */ taskId: number; /** Unix ms when the event was emitted. */ timestamp: number; /** Plugin version that emitted the event (useful for diagnostics). */ pluginVersion: string; /** Event-specific payload. */ data: T; } /** * Convenience event-payload shapes used by the plugin. * * These are exported so the frontend (and tests) can `import` them instead * of duplicating the literals. */ export interface TaskCreatedEventData { session: TaskSession; } export interface TaskUpdatedEventData { session: TaskSession; /** The new status the task transitioned to. */ newStatus: TaskSession["status"]; /** Previous status, if known. */ previousStatus?: TaskSession["status"]; } export interface TaskCompletedEventData { session: TaskSession; /** The terminal status the task ended in. */ terminalStatus: TaskSession["status"]; } export interface ToolRecordedEventData { session: TaskSession; /** The new tool call record that was just appended. */ toolCall: ToolCallRecord; } /** * v1.1.0+ payload for `operation.updated` events. Mirrors the shape * served by `/api/tasks/:id/operations` so the client can patch the * pipeline DOM in place (no re-fetch needed). */ export interface OperationUpdatedEventData { task: TaskSession; operations: Array<{ id: number; sequence: number; milestoneType: string; title: string; description: string; processDescription: string; timestamp: string; sessionShort: string; }>; fetchedAt: string; stale: boolean; } /** Convenience: a fully-typed event union. */ export type TypedTaskEvent = TaskEvent | TaskEvent | TaskEvent | TaskEvent; /** * Heartbeat interval (ms) — sent as a `:keep-alive` SSE comment so reverse * proxies / load balancers don't kill the connection. Set to 15s, which is * short enough to be useful and long enough not to waste bandwidth. */ export declare const SSE_HEARTBEAT_INTERVAL_MS = 15000; /** * The SSE comment we send as a keep-alive ping. Standard SSE convention is * to use a line starting with `:` so it is ignored by the EventSource parser. */ export declare const SSE_HEARTBEAT_PAYLOAD = ":keep-alive\n\n"; //# sourceMappingURL=types.d.ts.map