/** * Typed REST client for the TeamShare API (contract: docs/agent-tasks/ * agent-hub-connection.md). Envelope-aware, retrying, timeout-bound. */ import { AgentConfig } from "./config"; export declare const DEFAULT_API_URL = "https://api.teamshare.name.ng"; export declare const DEFAULT_WS_URL = "wss://api.teamshare.name.ng"; export declare class ApiError extends Error { readonly code: string; readonly status: number; readonly details: unknown; constructor(code: string, message: string, status: number, details?: unknown); } export declare class TeamshareApi { readonly baseUrl: string; readonly apiKey?: string | undefined; /** * Session mode carried as `X-TeamShare-Session-Mode` on every request: * 'run' | 'build' = execution (agents may self-assign), 'chat' | 'doc' = * conversation (self-assignment blocked, readyForDev forced off). */ readonly sessionMode?: string | undefined; constructor(baseUrl?: string, apiKey?: string | undefined, /** * Session mode carried as `X-TeamShare-Session-Mode` on every request: * 'run' | 'build' = execution (agents may self-assign), 'chat' | 'doc' = * conversation (self-assignment blocked, readyForDev forced off). */ sessionMode?: string | undefined); /** Reuses a config agent's credentials. Resolves key from secret store. */ static forAgent(baseUrl: string, agent: AgentConfig): TeamshareApi; private request; heartbeat(agentId: string, status: "online" | "working" | "offline", taskId?: string, sessionId?: string, force?: boolean): Promise; inbox(agentId: string): Promise<{ tasks: Array>; comments: Array>; mentions: Array>; chat: Array>; }>; /** * Agent steering (2026-09): pending human instructions for this session's * scope, marked delivered. Used by the `--self` loop; harnesses call the MCP * `get_instructions` tool directly. */ listInstructions(scope: { taskId?: string | null; projectId?: string | null; orchestratorTaskId?: string | null; channelId?: string | null; documentId?: string | null; }): Promise>; /** * Phase D settings snapshot for sessions spawned outside the daemon / * deep-link paths (which inject settings via flags): the CLI fetches this * so direct `run`/`chat`/`doc` sessions apply the agent's stored * model/temperature/maxTokens/systemPrompt (flag > agent > env > default). * The BYOK `providerKey` is only present under the agent's own key auth. */ getAgentSettings(agentId: string, timeoutMs?: number): Promise<{ userId?: string | null; /** Agent display name (the linked user's name). */ agentName?: string | null; /** Human user that created the agent. */ ownerId?: string | null; ownerName?: string | null; ownerEmail?: string | null; model: string | null; temperature: number | null; maxTokens: number | null; reasoningEffort: string | null; systemPrompt: string | null; harness: "auto" | "opencode" | "claude" | "codex" | "gemini" | "antigravity" | "copilot" | "goose" | "openhands" | "aider" | "none" | null; providerKey: string | null; /** Per-provider BYOK keys (provider slug -> plaintext; own-key auth only). */ providerKeys?: Record | null; /** Default working folder (per-agent linked folder). */ folderPath?: string | null; }>; /** * Agent self-service settings patch (`PATCH /agents/:id/settings`). * Currently only `folderPath` (null clears) - used by * `teamshare-agent set-folder --agent --path ` so the agent * can move its own working folder from any machine. */ patchAgentSettings(agentId: string, body: { folderPath?: string | null; }): Promise<{ id: string; folderPath: string | null; }>; /** Full project context (all sections + version). */ getProjectContext(projectId: string): Promise<{ overview: string | null; architecture: string | null; structure: string | null; workflows: string | null; conventions: string | null; gotchas: string | null; repoMapHash: string | null; /** Multi-folder pool: THIS identity's slice hash (drift detection). */ myRepoMapHash?: string | null; version: number; updatedAt: string; }>; /** Compact context digest injected into session briefs (may be empty). */ getProjectContextDigest(projectId: string): Promise<{ digest: string; }>; /** * Push a freshly scanned repo map into the project's cloud context * (structure section + optional workflows + tree hash). */ pushRepoMap(projectId: string, payload: { repoMapHash: string; structure: string; workflows?: string | null; filesSeen?: number; }): Promise<{ ok: boolean; version: number; }>; /** * Register a git repository on the server (multi-repo support). * Called by the bridge when linking a parent folder with discovered sub-repos. */ registerRepository(projectId: string, input: { name?: string; originUrl: string; defaultBranch?: string; remoteName?: string; provider?: string; }): Promise<{ id: string; projectId: string; originUrl: string; defaultBranch: string; }>; /** Partial section update (optimistic baseVersion check server-side). */ updateProjectContext(projectId: string, payload: Record): Promise<{ ok: boolean; version: number; }>; /** * Hub-side context reflection (IMP-912): the backend runs the merge LLM * pass with hub-resolved keys and persists the sections itself. */ reflectContext(projectId: string, payload: { taskTitle?: string; summary: string; }): Promise<{ ok: boolean; sections: string[]; version?: number; reason?: "no-key" | "no-signal" | "no-context" | "llm-error" | "write-error"; }>; mintRunToken(agentId: string, taskId?: string): Promise<{ token: string; expiresAt: string; }>; redeemRunToken(runToken: string, taskId?: string): Promise<{ wsToken: string; agentId: string; scopes: string[]; settings?: { model?: string | null; temperature?: number | null; maxTokens?: number | null; systemPrompt?: string | null; harness?: "auto" | "opencode" | "claude" | "codex" | "gemini" | "antigravity" | "copilot" | "goose" | "openhands" | "aider" | "none" | null; backgroundSessions?: boolean | null; }; }>; redeemLinkToken(linkToken: string): Promise<{ agentId: string; projectId: string; path: string | null; }>; setLinkedFolder(agentId: string, projectId: string, path: string, opts?: { siblingAgentIds?: string[]; machineId?: string; machineLabel?: string; }): Promise<{ id: string; folderPath: string | null; }>; /** Clears this machine's folder link for a project (owner's own machine). */ unlinkFolder(agentId: string, projectId: string, machineId: string): Promise<{ ok: true; }>; getTask(taskId: string): Promise; listTasks(params: { projectId?: string; status?: string; assigneeId?: string; page?: number; pageSize?: number; }): Promise; createTask(dto: { projectId: string; title: string; description?: string; status?: string; priority?: string; assigneeId?: string; dueDate?: string; tags?: string[]; readyForDev?: boolean; sortOrder?: number; documentIds?: string[]; }): Promise; listTaskDocuments(taskId: string): Promise; /** * Files uploaded directly to a task (the attachment system - separate from * project documents). Fails soft at call sites on older backends. */ listTaskAttachments(taskId: string): Promise; updateTask(taskId: string, dto: Record): Promise; /** * Reports that a planning pass has STARTED for the task. Increments the * task's plan-run counter + stamps the start time on the hub. Best-effort at * the call site; never changes the task status. */ startPlanRun(taskId: string, meta?: { harness?: string; model?: string; sessionId?: string; }): Promise<{ planRunCount: number; planLastRunAt: string | null; }>; /** * Reports a planning pass FINISHED. On success the hub sets the definitive * `plannedAt` marker; on failure it stores `planLastError`. */ finishPlanRun(taskId: string, result: { ok: boolean; summary?: string; error?: string; }): Promise<{ plannedAt: string | null; planRunCount: number; planLastError: string | null; }>; /** Claims the task (lease 10 min by default, renewed by heartbeat). Errors surface as thrown messages. */ claimTask(taskId: string, expiresMinutes?: number): Promise<{ claimed: boolean; claimedById: string; claimExpiresAt: string; }>; /** Releases the task claim (self-release or owner/admin takeover). */ releaseTask(taskId: string): Promise<{ released: boolean; claimedById: string | null; }>; /** Renews an active claim's lease without checking task status. */ renewClaim(taskId: string): Promise<{ renewed: boolean; claimExpiresAt: string; }>; /** * Session-scoped claim cleanup (2026-08-26): clears every claim THIS * session took. Called once when a chat/doc/run harness exits so an * agent forgetting release_task can never strand a lease. */ releaseSessionClaims(sessionId: string): Promise<{ released: number; }>; /** * Auto-run guard (2026-09): reports a harness-level failure (the run died * before producing work - provider outage, crashed CLI, missing binary) so * the hub can count consecutive failures and suspend the task instead of * letting the stranded-task sweep re-wake it forever. `suspended: true` means * no further automatic runs - a human must press "Run task". */ reportRunFailed(taskId: string, input?: { reason?: string; harness?: string; }): Promise<{ failures: number; suspended: boolean; cap: number; }>; listComments(taskId: string): Promise; /** Subtask tree of a task (nested, each node with checklist items). */ listSubtasks(taskId: string): Promise; createSubtask(dto: { taskId: string; title: string; parentId?: string | null; assigneeId?: string | null; dueDate?: string | null; }): Promise; /** Mark done / reopen, rename, reassign, move or re-due a subtask. */ updateSubtask(subtaskId: string, dto: Record): Promise; /** Lists checklist items on a task. */ listChecklistItems(taskId: string): Promise; /** Adds a checklist row to a task or a subtask (pass exactly one id). */ createChecklistItem(target: { taskId?: string; subtaskId?: string; }, title: string): Promise; /** Toggle done / rename a checklist row. */ updateChecklistItem(checklistItemId: string, dto: { title?: string; done?: boolean; }): Promise; /** Removes a checklist row. */ deleteChecklistItem(checklistItemId: string): Promise<{ id: string; deleted: boolean; }>; /** Document comment thread (Phase F document assistant). */ listDocumentComments(documentId: string): Promise; addComment(dto: { taskId?: string; documentId?: string; whiteboardId?: string; body: string; }): Promise; /** Board comment thread (board assistant / "Ask agent" on a board). */ listWhiteboardComments(whiteboardId: string): Promise; /** Board metadata + raw Excalidraw scene. */ getWhiteboard(whiteboardId: string): Promise<{ id: string; projectId: string; name: string; content?: unknown; updatedAt: string; }>; /** Agent-readable text extract of a board. */ extractWhiteboard(whiteboardId: string): Promise<{ text: string; truncated?: boolean; cached?: boolean; }>; /** Append a DiagramSpec to a board (deterministic server-side layout). */ drawOnWhiteboard(whiteboardId: string, spec: Record, expectedUpdatedAt?: string): Promise<{ id: string; updatedAt: string; applied: number; }>; getProject(projectId: string): Promise<{ id: string; name: string; status: string; /** Per-project working folder override for agents (null = none). */ folderPath?: string | null; /** IMP-914: agent git automation level ('none'|'commit'|'push'|'pr'). */ agentGitPolicy?: string | null; }>; /** Per-user folder links for a project (junction table). */ getLinkedFolders(projectId: string): Promise<{ items: Array<{ userId: string; path: string; name?: string; avatarUrl?: string; }>; }>; listDocuments(projectId: string, folderPath?: string): Promise<{ items: Document[]; }>; /** Virtual folder tree of a project (IMP-601). */ listDocumentFolders(projectId: string): Promise<{ folders: DocumentFolderNode[]; }>; /** Raw markdown body of a note document (IMP-601). */ getDocumentRaw(documentId: string): Promise<{ id: string; name: string; content: string; mime: string; }>; /** Creates a markdown note document (documents-driven workflow, IMP-601). */ createNoteDocument(dto: { projectId: string; name: string; content: string; folderPath?: string; }): Promise; /** * Agent-created Word document: the backend renders markdown to a .docx * file, uploads it to Cloudinary and records it as a file document. * Styling options match the tools-tab DOCX Report form so every path * (harness MCP, self mode, Tools tab) produces the same document. */ createRenderedDocument(dto: { projectId: string; name: string; content: string; folderPath?: string; subtitle?: string; author?: string; accentColor?: string; includeToc?: boolean; pageSize?: "a4" | "letter"; }): Promise; /** * Agent-created Excel workbook: the backend renders a structured table * spec to a styled .xlsx file and records it as a file document. */ createXlsxDocument(dto: { projectId: string; name: string; sheets: Array<{ name?: string; headers?: string[]; rows?: (string | number)[][]; freezeHeader?: boolean; columnWidths?: number[]; }>; folderPath?: string; }): Promise; /** * Downloads a public URL server-side and records it as a project file * document (research / file-harvester "download for me"). */ importFileFromUrl(dto: { projectId: string; url: string; name?: string; mime?: string; folderPath?: string; }): Promise; /** Replaces the markdown body of a note document (IMP-601). */ updateDocumentContent(documentId: string, content: string): Promise; getDocument(documentId: string): Promise<{ id: string; type: "link" | "file" | "note"; name: string; urlOrKey?: string | null; projectId: string; mime?: string | null; folderPath?: string; createdAt: string; }>; /** Phase F: extracted text for office/PDF documents. */ getDocumentExtract(documentId: string): Promise<{ text: string; truncated: boolean; format: string; cached: boolean; }>; listQueuedDocumentJobs(projectId: string): Promise; claimDocumentJob(jobId: string): Promise; markDocumentJobProcessing(jobId: string): Promise<{ ok: boolean; }>; jobUploadUrl(jobId: string): Promise<{ uploadUrl: string; folder: string; formParams: Record; }>; completeDocumentJob(jobId: string, body: { html?: string; url?: string; mime?: string; size?: number; name?: string; /** Pre-flight verdict: constructs the merge cannot preserve. */ unsupported?: string[]; /** Preservation report recorded on the resulting version. */ comment?: string; }): Promise<{ job: DocumentJob; versionNumber?: number; }>; failDocumentJob(jobId: string, error: string): Promise<{ job: DocumentJob; }>; /** * Downloads a document. Link docs return { url }; local files return plain * text; Cloudinary-hosted files return { url } (fetchable by the caller); * note documents return their markdown body (IMP-601). */ getDocumentContent(doc: Document): Promise; search(q: string, type?: string): Promise>>; /** * Similar prior work (tasks + documents) for a task, ranked by pg_trgm. * Compact rows only — fetch content with read_document / get_task. */ relatedForTask(taskId: string, limit?: number): Promise; /** Similar prior work (tasks + documents) for a tool run. */ relatedForRun(runId: string, limit?: number): Promise; /** Fuzzy similarity lookup by free-text subject. */ findSimilar(params: { q: string; projectId: string; type?: "all" | "task" | "document"; limit?: number; threshold?: number; }): Promise; listChatMessages(projectId: string, page?: number, pageSize?: number): Promise>; /** * Strip harness JSON events that the LLM sometimes echoes as reply text. * Removes lines matching {"type":"step_start",...}, {"type":"tool_use",...}, * {"type":"step_finish",...} etc. from opencode --format json output. */ private stripHarnessEvents; postChatMessage(projectId: string, body: string, channelId?: string): Promise>; /** Chat channels of a project (used to find/create `#agent-questions`). */ listChatChannels(projectId: string): Promise>; /** Creates a named channel; CHANNEL_NAME_TAKEN when it already exists. */ createChatChannel(projectId: string, name: string, description?: string): Promise<{ id: string; projectId: string; name: string; createdById: string; createdAt: string; }>; /** * The build queue of a project: pending ready-for-dev tasks in strict * order (sortOrder asc, createdAt asc), blocked tasks awaiting an answer * to an agent question, and the build agent (agentId + status). */ getBuildQueue(projectId: string): Promise; /** * Progress of the build run on this machine. Mirrors the whole run onto * the backend (bridge state kind 'build' + AgentLog transitions) so the * frontend can render live status from any device (IMP-630 pattern). */ pushBuildProgress(agentId: string, body: { projectId: string; status: "running" | "finished" | "stopped" | "blocked"; total: number; done: number; remaining: number; currentTaskId?: string; currentTitle?: string; skippedTaskId?: string; }): Promise<{ ok: true; }>; /** * The task's OPEN agent question, or null when answered/none (thread + * #agent-questions channel aware). The build loop polls this to detect * answered questions and resume skipped build tasks (IMP-700). */ getTaskQuestions(taskId: string): Promise<{ open: { commentId: string; body: string; askedBy: { id: string; name: string; }; askedAt: string; } | null; }>; /** * Posts an automatic bridge diagnostic report (crash/error/warning) with * full context. The server upserts by `(agentId, fingerprint)` so a * recurring problem bumps `occurrences` instead of flooding the table. */ reportDiagnostic(agentId: string, body: { kind: string; severity: 'fatal' | 'error' | 'warning'; message: string; errorCode?: string; stack?: string; fingerprint?: string; context?: Record; doctorReport?: string; logTail?: string; }): Promise<{ id: string; status: string; occurrences: number; }>; /** Pushes per-agent busy/queued/kind + linked-project folders to the backend. */ pushBridgeState(agentId: string, body: { busy: boolean; kind?: "task" | "chat" | "doc" | "board" | "build" | "orchestrator" | "tool"; since?: string; taskId?: string; queued: number; machineId?: string; machineLabel?: string; projects: Record; }): Promise<{ ok: true; }>; /** * Reports the harness-native session id for a run (once per run, best * effort). Lets the cloud correlate a TeamShare session with its harness * conversation. Never throws from the caller's perspective (callers use * `.catch(() => {})`). */ reportHarnessSession(agentId: string, body: { taskId?: string; mode: string; harness: string; harnessSessionId: string; }): Promise<{ ok: true; sessionId?: string; }>; getOrchestratorWork(agentId: string): Promise; mergeOrchestratorTask(otId: string): Promise<{ success: boolean; conflictFiles?: string[]; }>; /** IMP-919: worker self-report - this run died without completing the task. */ reportOrchestratorWorkerFailed(otId: string, reason: string): Promise<{ ok: boolean; status: string; }>; claimOrchestratorBySourceTask(sourceTaskId: string): Promise<{ otId: string; } | null>; listToolCatalog(): Promise<{ tools: Array<{ key: string; title: string; description: string; category: string; outputs: string[]; estSeconds: number; }>; }>; createToolRun(projectId: string, toolKey: string, params: Record): Promise; getToolRun(runId: string): Promise; /** * Per-run ephemeral secrets (browser auto-answer): the browser agent key + * optional provider key / base URL supplied on the run form. Agent-key auth * only; returns null when none were provided or they expired. */ getToolRunSecrets(runId: string): Promise<{ browserKey: string | null; providerKey: string | null; provider: string | null; baseUrl: string | null; expiresAt: string; } | null>; /** Validate a superadmin-issued browser agent key before a browse session. */ validateBrowserAgentKey(key: string): Promise<{ valid: boolean; user: { id: string; name: string | null; email: string | null; }; agent: { id: string; userId: string; }; label: string; remainingUses: number | null; expiresAt: string | null; }>; listToolRuns(projectId: string, page?: number, pageSize?: number): Promise; cancelToolRun(runId: string): Promise<{ cancelled: boolean; }>; appendToolLog(runId: string, lines: Array<{ stream: string; text: string; }>, progress?: Record): Promise<{ ok: boolean; }>; uploadToolOutput(runId: string, fileBuffer: Buffer, fileName: string, mime: string): Promise; /** * Marks an agent-driven (harness/self) tool run terminal and records * progress. The backend moves the backing task to in_review. */ completeToolRun(runId: string, body: { status?: "completed" | "failed"; progress?: Record; errorSummary?: string; }): Promise; plannerComplete(body: { planTaskId: string; mode: string; tasks: unknown[]; orderedTaskIds: string[]; dependencies: unknown[]; planMarkdown?: string; acceptanceCriteria?: string; planSummary?: string; planTitle?: string; }): Promise<{ delivered: boolean; }>; } export interface ToolRun { id: string; projectId: string; toolKey: string; execution: string; status: "pending" | "running" | "completed" | "failed" | "cancelled"; params?: Record | null; agentId?: string | null; createdBy: string; outputDocumentIds: string[]; chainedFromId?: string | null; log?: Array<{ stream: string; text: string; at: string; }> | null; errorSummary?: string | null; durationMs?: number | null; costCents?: number | null; /** Tools-as-tasks: task kind / tool key / back-link + live progress. */ kind?: string | null; taskId?: string | null; progress?: Record | null; /** Originating recurring schedule id, when run by the scheduler. */ scheduleId?: string | null; /** Typed Tool Task spec snapshot (joined from the backing task). */ spec?: ToolTaskSpec | null; /** Backing task title (joined server-side). */ taskTitle?: string | null; /** Live task progress mirrored from the backing task. */ toolProgress?: Record | null; startedAt: string; endedAt?: string | null; createdAt: string; updatedAt: string; } /** Declared column in a data-collection contract. */ export interface ToolColumnSpec { key: string; label: string; type: "string" | "number" | "date" | "url" | "email" | "boolean"; required?: boolean; citationRequired?: boolean; example?: string; } /** Frozen spec snapshot attached to a tool run (from the backing task). */ export interface ToolTaskSpec { toolKey: string; toolTitle: string; /** Short Subject for deliverable file names (task title minus tool prefix). */ baseName?: string; execution: string; kind: "tool" | "research"; recipe: { id: string; version: number; steps: string[]; }; outputContract: { folders: string[]; documents: Array<{ type: string; name: string; label?: string; required?: boolean; }>; manifest: boolean; }; columns: ToolColumnSpec[]; requiredCapabilities: string[]; requiredMcpTools: string[]; /** Outreach delivery: recipients are read from these deliverable columns. */ supportsEmailDelivery?: boolean; emailRecipientColumns?: string[]; emailNameColumns?: string[]; capabilityCheck: { ok: boolean; missing: string[]; reason: string | null; }; specVersion: number; createdAt: string; } /** * One compact similarity hit from `/search/similar|related/*` (pg_trgm). * No content — fetch it with read_document / get_task. */ export interface SimilarRow { kind: "task" | "document"; id: string; title: string; /** 0-1 pg_trgm score. */ score: number; status?: string; folderPath?: string | null; createdAt: string; } export interface Task { id: string; title: string; description?: string | null; status: string; priority: string; projectId: string; assigneeId?: string | null; dueDate?: string | null; tags?: string[]; readyForDev?: boolean; sortOrder?: number; /** Plan mode: acceptance criteria (markdown), maintained by the planner. */ acceptanceCriteria?: string | null; /** Nested sub-task of a plan task (orchestrator planning). */ parentTaskId?: string | null; workMode?: "plan" | "build"; /** Plan-run tracking (2026-09): definitive planned marker + run count. */ plannedAt?: string | null; planRunCount?: number; planLastRunAt?: string | null; planLastError?: string | null; /** Typed Tool Task fields (kind = tool|research). */ kind?: "code" | "tool" | "research"; toolKey?: string | null; toolParams?: Record | null; toolSpec?: ToolTaskSpec | null; toolProgress?: Record | null; toolRunId?: string | null; createdAt: string; updatedAt?: string; project?: { id: string; name: string; } | null; comments?: Comment[]; } export interface TaskDocument { id: string; name: string; type: string; folderPath?: string | null; mime?: string | null; size?: number | null; createdAt: string; uploader?: { id: string; name: string; avatarUrl?: string | null; } | null; } /** * A file uploaded directly to a task or one of its comments (the separate * attachment system - distinct from project documents). */ export interface TaskAttachment { id: string; taskId?: string | null; commentId?: string | null; fileKey?: string; url?: string | null; name: string; mime: string | null; sizeBytes?: number | null; target?: "task" | "comment"; uploadedBy?: string; createdAt: string; uploader?: { id: string; name: string; avatarUrl?: string | null; kind?: string; } | null; } export interface Comment { id: string; taskId?: string | null; documentId?: string | null; body: string; author?: { id: string; name: string; kind?: string; } | null; authorId?: string; createdAt: string; } export interface ChecklistItemRow { id: string; title: string; done: boolean; sortOrder?: number; } export interface SubtaskNode { id: string; taskId: string; parentId?: string | null; title: string; done: boolean; assigneeId?: string | null; dueDate?: string | null; sortOrder: number; createdBy: string; createdAt: string; updatedAt: string; assignee?: { id: string; name: string; kind?: string; } | null; creator?: { id: string; name: string; kind?: string; } | null; children?: SubtaskNode[]; checklistItems?: ChecklistItemRow[]; } export interface Document { id: string; projectId: string; type: "link" | "file" | "note"; urlOrKey: string; name: string; mime?: string | null; /** Virtual folder path (IMP-601); "/" is the root. */ folderPath?: string; createdAt: string; } /** One node of the virtual folder tree (IMP-601). */ export interface DocumentFolderNode { path: string; name: string; children: DocumentFolderNode[]; documentCount: number; } /** * A deterministic file-processing job for the document editing pipeline * (2026-09). The bridge claims it, converts with LibreOffice WASM, uploads the * result and completes it - no model calls anywhere. */ export interface DocumentJob { id: string; documentId: string; projectId: string; kind: "docx_to_html" | "html_to_docx" | "text_commit" | "sheet_commit" | "export"; purpose: "prepare" | "commit" | "download"; status: "queued" | "claimed" | "processing" | "succeeded" | "failed" | "superseded" | "cancelled"; targetFormat?: string | null; sourceFormat?: string | null; baseVersionNumber?: number | null; attempts: number; error?: string | null; /** Only present on the claim response - the converter's full input. */ payload?: { sourceUrl?: string | null; sourceMime?: string | null; fileName?: string | null; html?: string; targetFormat?: string; [key: string]: unknown; }; } /** Build-mode queue snapshot (IMP-700): strict order + blocked + agent. */ export interface BuildQueue { project: { id: string; name: string; }; buildAgent: { id: string; name: string; status: string; } | null; pending: Array<{ position: number; task: Task; }>; blocked: Array<{ task: Task; question: { commentId: string; body: string; askedBy: { id: string; name: string; }; askedAt: string; }; }>; /** Orchestrator flow config per task (model + escalation + verification + worktree). */ flows?: Record; } export interface BuildProgressBody { projectId: string; status: "running" | "finished" | "stopped" | "blocked"; total: number; done: number; remaining: number; currentTaskId?: string; currentTitle?: string; skippedTaskId?: string; } export interface OrchestratorWorkItem { orchestratorTaskId: string; taskId: string | null; title: string; description: string | null; projectId: string; worktreePath: string | null; branchName: string | null; /** chainMode: previous completed group task's branch to build on. */ baseBranch: string | null; integrationBranch: string | null; preferredModel: string | null; verificationSteps: string[]; attemptCount: number; maxAttempts: number; localMode: boolean; }