From 0120f7aa931c471ea02e88f7c7afa9a9275cb78d Mon Sep 17 00:00:00 2001 From: Bersabel Tadesse Date: Thu, 23 Jul 2026 00:03:55 -0700 Subject: [PATCH 1/4] Add conservative thread organizer plugin --- README.md | 12 +- package-lock.json | 24 + plugins/thread-organizer/README.md | 62 + plugins/thread-organizer/core.test.ts | 206 + plugins/thread-organizer/core.ts | 390 + plugins/thread-organizer/docs/screenshot.png | Bin 0 -> 122460 bytes plugins/thread-organizer/package.json | 42 + plugins/thread-organizer/server.test.ts | 312 + plugins/thread-organizer/server.ts | 514 + plugins/thread-organizer/tsconfig.json | 29 + .../types/bb-plugin-sdk-app.d.ts | 794 ++ .../thread-organizer/types/bb-plugin-sdk.d.ts | 11762 ++++++++++++++++ 12 files changed, 14146 insertions(+), 1 deletion(-) create mode 100644 plugins/thread-organizer/README.md create mode 100644 plugins/thread-organizer/core.test.ts create mode 100644 plugins/thread-organizer/core.ts create mode 100644 plugins/thread-organizer/docs/screenshot.png create mode 100644 plugins/thread-organizer/package.json create mode 100644 plugins/thread-organizer/server.test.ts create mode 100644 plugins/thread-organizer/server.ts create mode 100644 plugins/thread-organizer/tsconfig.json create mode 100644 plugins/thread-organizer/types/bb-plugin-sdk-app.d.ts create mode 100644 plugins/thread-organizer/types/bb-plugin-sdk.d.ts diff --git a/README.md b/README.md index 336a017..f6f85ec 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # bb plugins -Four bb plugins I use for product design work, kept together with the few build and repository tools they share. [![CI](https://github.com/brsbl/bb-plugins/actions/workflows/ci.yml/badge.svg)](https://github.com/brsbl/bb-plugins/actions/workflows/ci.yml) +Five bb plugins I use for product design work, kept together with the few build and repository tools they share. [![CI](https://github.com/brsbl/bb-plugins/actions/workflows/ci.yml/badge.svg)](https://github.com/brsbl/bb-plugins/actions/workflows/ci.yml) [bb](https://getbb.app) is an agentic IDE for running coding agents across projects, threads, and environments. Its plugins can add UI, commands, skills, and server capabilities; this repository is where I build and maintain mine. @@ -38,6 +38,16 @@ Lets you peek at a thread's status and repository context without leaving the si Install: `bb plugin install git:https://github.com/brsbl/bb-plugins.git@plugin/thread-hover-cards --yes` +### Thread Organizer + +Files new threads into the right existing work section while preserving native titles and every manual override. + +![Thread Organizer settings in bb](plugins/thread-organizer/docs/screenshot.png) + +[Source](plugins/thread-organizer) · [README](plugins/thread-organizer/README.md) + +Install: `bb plugin install git:https://github.com/brsbl/bb-plugins.git@plugin/thread-organizer --yes` + ### UI Patterns Puts proven UI components and interaction guidance within reach of both designers and agents. diff --git a/package-lock.json b/package-lock.json index e9a711b..8da825e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4005,6 +4005,10 @@ "resolved": "plugins/thread-hover-cards", "link": true }, + "node_modules/bb-plugin-thread-organizer": { + "resolved": "plugins/thread-organizer", + "link": true + }, "node_modules/bb-plugin-ui-patterns": { "resolved": "plugins/ui-patterns", "link": true @@ -6678,6 +6682,26 @@ "bbPluginSdk": "^0.4.0" } }, + "plugins/thread-organizer": { + "name": "bb-plugin-thread-organizer", + "version": "0.1.0", + "license": "UNLICENSED", + "devDependencies": { + "@bb/plugin-sdk": "file:../../tooling/vendor/bb-plugin-sdk-0.4.0.tgz", + "@types/better-sqlite3": "^7.6.12", + "@types/node": "^22.0.0", + "better-sqlite3": "^12.10.0", + "cron-parser": "^5.5.0", + "hono": "^4.11.9", + "typescript": "^5.7.0", + "vitest": "^4.1.8", + "zod": "^4.3.6" + }, + "engines": { + "bb": ">=0.0.34", + "bbPluginSdk": "^0.4.0" + } + }, "plugins/ui-patterns": { "name": "bb-plugin-ui-patterns", "version": "0.1.0", diff --git a/plugins/thread-organizer/README.md b/plugins/thread-organizer/README.md new file mode 100644 index 0000000..4de7de7 --- /dev/null +++ b/plugins/thread-organizer/README.md @@ -0,0 +1,62 @@ +# Thread Organizer + +Thread Organizer files new bb threads into existing work sections while leaving manual organization in control. It starts in observe mode and never creates sections, backfills old threads, or runs a hidden classification agent. + +![Thread Organizer settings in bb](docs/screenshot.png) + +## Install + +```bash +bb plugin install git:https://github.com/brsbl/bb-plugins.git@plugin/thread-organizer --yes +``` + +## Use + +Leave the plugin in its default `observe` mode first and inspect its decisions: + +```bash +bb plugin logs thread-organizer -f +``` + +When the proposals look right, enable changes: + +```bash +bb plugin config thread-organizer set mode apply +``` + +The setting takes effect immediately. + +| Existing section | Automatic use | +| --- | --- | +| `bb` or `bb quick fixes` | bb engineering work | +| `Extensions` | Plugins, skills, automations, and agent tooling | +| `Design` | Design systems, UI patterns, information architecture, and API-surface work | +| `Writing` | Articles, positioning, copy, and editorial work | +| `QA` | Never; reserved for manual phase management | + +Threads that do not clear the confidence threshold stay unsectioned. Pinning remains independent priority state, and archiving remains completion state. + +## Behavior + +| Moment | Evaluation | +| --- | --- | +| Creation | Uses project identity and the prompt-derived title fallback for an early section proposal | +| Activation | Retries prompt history briefly when the initial prompt was not yet available | +| First completed turn | Refines the section and repairs a still-missing title | +| Later turns | Re-evaluates at turns 5, 15, 25, and every ten completed turns thereafter | + +New placements require at least `0.85` confidence with a `0.20` lead over the next rule. Moving a plugin-managed thread requires `0.92` confidence, a `0.25` lead, and the same result at two consecutive scheduled evaluations. + +Only visible, ordinary user root threads created while the plugin is loaded are tracked. Hidden workers, children, forks, side chats, plugin-originated threads, archived threads, deleted threads, and terminal error states are excluded. + +An explicit creation-time title or section is locked. After the plugin writes a field, any different value is treated as a manual or external override and locks that field permanently. Native bb titles therefore win, and section changes are never cleared automatically. + +## Develop + +From the monorepo root: + +```bash +npm ci +npm run check --workspace=bb-plugin-thread-organizer +bb plugin install "path:$PWD/plugins/thread-organizer" --yes +``` diff --git a/plugins/thread-organizer/core.test.ts b/plugins/thread-organizer/core.test.ts new file mode 100644 index 0000000..3f380b4 --- /dev/null +++ b/plugins/thread-organizer/core.test.ts @@ -0,0 +1,206 @@ +import { describe, expect, it } from "vitest"; + +import { + advanceEvaluationMilestone, + classifySection, + deriveTaskTitle, + isEligibleThread, + resolveSectionId, +} from "./core.js"; + +describe("thread eligibility", () => { + const eligible = { + archivedAt: null, + childOrigin: null, + deletedAt: null, + originKind: null, + originPluginId: null, + parentThreadId: null, + sourceThreadId: null, + status: "idle" as const, + visibility: "visible" as const, + }; + + it("accepts ordinary root threads, including pinned threads by implication", () => { + expect(isEligibleThread(eligible)).toBe(true); + }); + + it.each([ + { ...eligible, archivedAt: 1 }, + { ...eligible, deletedAt: 1 }, + { ...eligible, parentThreadId: "thr_parent" }, + { ...eligible, sourceThreadId: "thr_source" }, + { ...eligible, originKind: "side-chat" as const }, + { ...eligible, childOrigin: "fork" as const }, + { ...eligible, originPluginId: "automations" }, + { ...eligible, status: "error" as const }, + { ...eligible, visibility: "hidden" as const }, + ])("rejects protected thread shape %#", (thread) => { + expect(isEligibleThread(thread)).toBe(false); + }); +}); + +describe("section classification", () => { + it.each([ + { + expected: "bb", + projectName: "bb", + texts: ["Review the recent plugin API changes and harden them."], + title: "Plugin API review and hardening", + }, + { + expected: "bb", + projectName: "bb", + texts: ["can you make a prod build from latest origin/main?"], + title: "bb integration branch", + }, + { + expected: "extensions", + projectName: "Personal", + texts: [ + "Create a bb plugin that automatically renames and reorganizes threads.", + ], + title: "Auto Rename and Reorganize", + }, + { + expected: "extensions", + projectName: "bb plugins", + texts: ["Design and implement the Omegacode plugin workflow overview."], + title: "Omegacode workflow overview design pass", + }, + { + expected: "extensions", + projectName: "Design Doctrine", + texts: ["Rewrite the doctrine docs."], + title: "Rewrite doctrine docs", + }, + { + expected: "design", + projectName: "UI Pattern Atlas", + texts: ["Take over the UI Patterns work."], + title: "atlas", + }, + { + expected: "design", + projectName: "moss", + texts: ["Continue the design↔code system work."], + title: "design↔code", + }, + { + expected: "design", + projectName: "moss", + texts: ["Spec the right API surface for the Moss agent."], + title: "Moss Agent API Surface", + }, + { + expected: "writing", + projectName: "moss", + texts: ["Help me work on positioning for Moss."], + title: "moss positioning", + }, + { + expected: "writing", + projectName: "Personal", + texts: ["Write a blog post about creating loops."], + title: "Creating Loops Blog Post", + }, + { + expected: "bb", + projectName: "bb", + texts: ["https://github.com/ymichael/bb/issues/603"], + title: "Issue 603", + }, + ])("classifies $title as $expected", ({ expected, projectName, texts }) => { + expect(classifySection({ projectName, texts })?.target).toBe(expected); + }); + + it("abstains from weak personal-workspace intent", () => { + expect( + classifySection({ + projectName: "Personal", + texts: ["clean up disk space and CPU"], + }), + ).toBeNull(); + }); + + it("surfaces a low margin instead of hiding mixed bb design intent", () => { + const decision = classifySection({ + projectName: "bb", + texts: ["Design a durable UI pattern system."], + }); + expect(decision).toMatchObject({ + runnerUp: "bb", + target: "design", + }); + expect(decision?.margin).toBeCloseTo(0.05); + }); +}); + +describe("existing section resolution", () => { + it("supports the bb quick fixes migration alias", () => { + expect( + resolveSectionId( + [ + { id: "sec_bb", name: "bb quick fixes" }, + { id: "sec_design", name: "Design" }, + ], + "bb", + ), + ).toBe("sec_bb"); + }); + + it("fails closed when both bb aliases exist", () => { + expect( + resolveSectionId( + [ + { id: "sec_bb", name: "bb" }, + { id: "sec_old", name: "bb quick fixes" }, + ], + "bb", + ), + ).toBeNull(); + }); + + it("never treats QA as a target alias", () => { + expect( + resolveSectionId([{ id: "sec_qa", name: "QA" }], "design"), + ).toBeNull(); + }); +}); + +describe("conservative title repair", () => { + it.each([ + ["can you optimize my CI?", "Optimize CI"], + ["Please fix the external file nav.", "Fix External File Nav"], + ["take over tools hub refactor PR", "Take Over Tools Hub Refactor"], + ["clean up disk space and CPU", "Clean Up Disk Space"], + ])("derives %s", (prompt, expected) => { + expect(deriveTaskTitle(prompt)?.title).toBe(expected); + }); + + it.each([ + "continue", + "root cause this", + "https://github.com/ymichael/bb/issues/603", + "create a bb plugin", + "what should we do next?", + ])("abstains from %s", (prompt) => { + expect(deriveTaskTitle(prompt)).toBeNull(); + }); +}); + +describe("turn milestones", () => { + it.each([ + [1, 1, 5], + [1, 4, 5], + [1, 5, 15], + [5, 14, 15], + [5, 15, 25], + [15, 37, 45], + ])( + "advances current %i after %i completed turns to %i", + (current, turns, expected) => { + expect(advanceEvaluationMilestone(current, turns)).toBe(expected); + }, + ); +}); diff --git a/plugins/thread-organizer/core.ts b/plugins/thread-organizer/core.ts new file mode 100644 index 0000000..7142639 --- /dev/null +++ b/plugins/thread-organizer/core.ts @@ -0,0 +1,390 @@ +export const SECTION_TARGETS = [ + "bb", + "extensions", + "design", + "writing", +] as const; + +export type SectionTarget = (typeof SECTION_TARGETS)[number]; + +export interface OrganizableThread { + archivedAt: number | null; + childOrigin: "fork" | "side-chat" | null; + deletedAt: number | null; + originKind: "fork" | "side-chat" | null; + originPluginId: string | null; + parentThreadId: string | null; + sourceThreadId: string | null; + status: "active" | "error" | "idle" | "starting" | "stopping"; + visibility: "hidden" | "visible"; +} + +export interface SectionClassification { + confidence: number; + margin: number; + reasons: string[]; + runnerUp: SectionTarget | null; + target: SectionTarget; +} + +export interface SectionDescriptor { + id: string; + name: string; +} + +export interface TitleCandidate { + confidence: number; + title: string; +} + +const SECTION_ALIASES: Record = { + bb: ["bb", "bb quick fixes"], + design: ["design"], + extensions: ["extensions"], + writing: ["writing"], +}; + +const LOW_INFORMATION = new Set([ + "continue", + "do it", + "fix", + "go ahead", + "help", + "help me", + "investigate", + "ok", + "okay", + "proceed", + "root cause this", + "sounds good", + "yes", +]); + +const ACTION_PATTERNS: Array<{ + expression: RegExp; + title: string; +}> = [ + { expression: /^take\s+over\b/i, title: "Take Over" }, + { expression: /^clean\s+up\b/i, title: "Clean Up" }, + { expression: /^root\s+cause\b/i, title: "Investigate" }, + { expression: /^investigate\b/i, title: "Investigate" }, + { expression: /^implement\b/i, title: "Implement" }, + { expression: /^optimize\b/i, title: "Optimize" }, + { expression: /^reorganize\b/i, title: "Reorganize" }, + { expression: /^refactor\b/i, title: "Refactor" }, + { expression: /^analyze\b/i, title: "Analyze" }, + { expression: /^create\b/i, title: "Create" }, + { expression: /^design\b/i, title: "Design" }, + { expression: /^rewrite\b/i, title: "Rewrite" }, + { expression: /^refresh\b/i, title: "Refresh" }, + { expression: /^profile\b/i, title: "Profile" }, + { expression: /^review\b/i, title: "Review" }, + { expression: /^rename\b/i, title: "Rename" }, + { expression: /^update\b/i, title: "Update" }, + { expression: /^render\b/i, title: "Render" }, + { expression: /^archive\b/i, title: "Archive" }, + { expression: /^debug\b/i, title: "Debug" }, + { expression: /^build\b/i, title: "Build" }, + { expression: /^write\b/i, title: "Write" }, + { expression: /^style\b/i, title: "Style" }, + { expression: /^move\b/i, title: "Move" }, + { expression: /^open\b/i, title: "Open" }, + { expression: /^audit\b/i, title: "Audit" }, + { expression: /^add\b/i, title: "Add" }, + { expression: /^fix\b/i, title: "Fix" }, +]; + +const GENERIC_TITLE_WORDS = new Set([ + "agent", + "automation", + "bb", + "issue", + "plugin", + "problem", + "task", + "thing", + "this", + "thread", +]); + +const TITLE_CONNECTORS = new Set([ + "and", + "for", + "from", + "in", + "of", + "on", + "or", + "to", + "with", +]); + +const TITLE_ACRONYMS = new Set([ + "api", + "bb", + "ci", + "cpu", + "css", + "ds", + "html", + "http", + "https", + "mcp", + "pr", + "qa", + "sdk", + "ui", + "url", + "ux", +]); + +function normalize(value: string): string { + return value + .normalize("NFKC") + .replace(/\r\n?/g, "\n") + .replace(/[ \t]+/g, " ") + .trim() + .toLowerCase(); +} + +function matches(value: string, expression: RegExp): boolean { + expression.lastIndex = 0; + return expression.test(value); +} + +export function isSubstantiveText(value: string): boolean { + const normalized = normalize(value) + .replace(/^\/[a-z0-9:_-]+\s*/i, "") + .replace(/[.!?]+$/g, "") + .trim(); + if (normalized.length < 4 || LOW_INFORMATION.has(normalized)) return false; + return !/^(?:https?:\/\/\S+|@[a-z0-9:_-]+)$/i.test(normalized); +} + +export function isEligibleThread(thread: OrganizableThread): boolean { + return ( + thread.visibility === "visible" && + thread.parentThreadId === null && + thread.sourceThreadId === null && + thread.originKind === null && + thread.childOrigin === null && + thread.originPluginId === null && + thread.archivedAt === null && + thread.deletedAt === null && + thread.status !== "error" && + thread.status !== "stopping" + ); +} + +function setScore( + scores: Map, + target: SectionTarget, + confidence: number, + reason: string, +): void { + const current = scores.get(target); + if (current === undefined || confidence > current.confidence) { + scores.set(target, { confidence, reasons: [reason] }); + return; + } + if (confidence === current.confidence && !current.reasons.includes(reason)) { + current.reasons.push(reason); + } +} + +export function classifySection(input: { + projectName: string; + texts: string[]; +}): SectionClassification | null { + const project = normalize(input.projectName); + const substantive = input.texts.filter(isSubstantiveText).map(normalize); + const corpus = substantive.join("\n"); + const scores = new Map< + SectionTarget, + { confidence: number; reasons: string[] } + >(); + + if ( + matches( + corpus, + /\b(blog(?:\s+post)?|article|essay|positioning|product copy|website copy|editorial)\b/i, + ) + ) { + setScore(scores, "writing", 0.96, "explicit editorial intent"); + } + + if ( + project === "ui pattern atlas" || + matches( + corpus, + /\b(design system|ui patterns?|information architecture|interaction model|product direction|api surface|figma)\b|design\s*[↔<>-]\s*code/i, + ) + ) { + setScore( + scores, + "design", + project === "ui pattern atlas" ? 0.97 : 0.95, + project === "ui pattern atlas" + ? "design project identity" + : "durable design-system intent", + ); + } + + if ( + ["bb plugins", "prompt shaper"].includes(project) || + (project !== "bb" && + matches( + corpus, + /\b(bb\s+plugin|plugin|skill|automation|agent tool|agent tooling)\b/i, + )) + ) { + setScore( + scores, + "extensions", + project === "bb plugins" || project === "prompt shaper" ? 0.98 : 0.96, + project === "bb plugins" || project === "prompt shaper" + ? "extension project identity" + : "explicit extension intent", + ); + } else if (project === "design doctrine") { + setScore(scores, "extensions", 0.9, "extension project identity"); + } + + if (project === "bb") { + setScore(scores, "bb", 0.9, "bb project identity"); + if ( + matches( + corpus, + /\b(fix|debug|investigate|implement|build|review|refactor|test|ci|server|daemon|sync|branch|pull request|pr\s*#?\d+|issue\s*#?\d+)\b/i, + ) + ) { + setScore(scores, "bb", 0.96, "bb engineering intent"); + } + } + + const ranked = [...scores.entries()] + .map(([target, value]) => ({ target, ...value })) + .sort( + (left, right) => + right.confidence - left.confidence || + left.target.localeCompare(right.target), + ); + const winner = ranked[0]; + if (winner === undefined) return null; + const runnerUp = ranked[1] ?? null; + return { + confidence: winner.confidence, + margin: winner.confidence - (runnerUp?.confidence ?? 0), + reasons: winner.reasons, + runnerUp: runnerUp?.target ?? null, + target: winner.target, + }; +} + +export function resolveSectionId( + sections: SectionDescriptor[], + target: SectionTarget, +): string | null { + const aliases = new Set(SECTION_ALIASES[target]); + const matches = sections.filter((section) => + aliases.has(normalize(section.name)), + ); + return matches.length === 1 ? matches[0]!.id : null; +} + +function stripPromptPreamble(value: string): string { + let result = value + .normalize("NFKC") + .replace(/\r\n?/g, "\n") + .replace(/^\s*(?:[-*]|\d+[.)])\s+/, "") + .replace(/^\/[a-z0-9:_-]+\s+/i, "") + .trim(); + const preambles = [ + /^(?:can|could|would)\s+you\s+/i, + /^can\s+i\s+/i, + /^please\s+/i, + /^i\s+(?:want|need)\s+to\s+/i, + /^i(?:'d| would)\s+like\s+to\s+/i, + /^help\s+me\s+(?:to\s+)?/i, + /^let(?:'s| us)\s+/i, + ]; + for (const preamble of preambles) result = result.replace(preamble, ""); + return result.trim(); +} + +function displayTitleWord(word: string, index: number): string { + const lower = word.toLowerCase(); + if (TITLE_ACRONYMS.has(lower)) return lower.toUpperCase(); + if (index > 0 && TITLE_CONNECTORS.has(lower)) return lower; + if (/[0-9↔<>+#./-]/.test(word) && /[A-Z]/.test(word)) return word; + return `${word.charAt(0).toUpperCase()}${word.slice(1).toLowerCase()}`; +} + +export function deriveTaskTitle(value: string): TitleCandidate | null { + let prompt = stripPromptPreamble(value); + if ( + prompt.length === 0 || + /^(?:https?:\/\/|@)/i.test(prompt) || + !isSubstantiveText(prompt) + ) { + return null; + } + + const action = ACTION_PATTERNS.find(({ expression }) => + matches(prompt, expression), + ); + if (action === undefined) return null; + prompt = prompt.replace(action.expression, "").trim(); + prompt = prompt + .split(/\b(?:so that|because|and then|then|which|that)\b|[\n.!?;:]/i, 1)[0]! + .replace(/^[\s"'`([{]+|[\s"'`\])}]+$/g, "") + .trim(); + + const words = + prompt.match(/[A-Za-z0-9][A-Za-z0-9+#./↔<>-]*/g)?.filter(Boolean) ?? []; + while ( + words.length > 0 && + /^(?:a|an|my|our|the|this|these|those)$/i.test(words[0]!) + ) { + words.shift(); + } + + const actionWordCount = action.title.split(/\s+/).length; + const objectWords = words.slice(0, Math.max(1, 5 - actionWordCount)); + while ( + objectWords.length > 0 && + TITLE_CONNECTORS.has(objectWords.at(-1)!.toLowerCase()) + ) { + objectWords.pop(); + } + const specificWords = objectWords.filter((word) => { + const normalized = word.toLowerCase(); + return ( + !GENERIC_TITLE_WORDS.has(normalized) && + !TITLE_CONNECTORS.has(normalized) && + normalized.length > 1 + ); + }); + if (objectWords.length === 0 || specificWords.length === 0) return null; + + const objectTitle = objectWords + .map((word, index) => displayTitleWord(word, index + actionWordCount)) + .join(" "); + return { + confidence: 0.92, + title: `${action.title} ${objectTitle}`.trim(), + }; +} + +export function nextEvaluationMilestone(current: number): number { + return current <= 1 ? 5 : current + 10; +} + +export function advanceEvaluationMilestone( + current: number, + completedTurns: number, +): number { + let next = current; + while (next <= completedTurns) next = nextEvaluationMilestone(next); + return next; +} diff --git a/plugins/thread-organizer/docs/screenshot.png b/plugins/thread-organizer/docs/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..5504fa94f7d8a97aa4288ea4473e15ed457f2698 GIT binary patch literal 122460 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.0.34", + "bbPluginSdk": "^0.4.0" + }, + "bb": { + "name": "Thread Organizer", + "description": "Organizes new bb threads into existing sections while preserving manual changes.", + "branding": { + "icon": "FolderTree" + }, + "server": "./server.ts", + "skills": [] + }, + "devDependencies": { + "@bb/plugin-sdk": "file:../../tooling/vendor/bb-plugin-sdk-0.4.0.tgz", + "@types/better-sqlite3": "^7.6.12", + "@types/node": "^22.0.0", + "better-sqlite3": "^12.10.0", + "cron-parser": "^5.5.0", + "hono": "^4.11.9", + "typescript": "^5.7.0", + "vitest": "^4.1.8", + "zod": "^4.3.6" + } +} diff --git a/plugins/thread-organizer/server.test.ts b/plugins/thread-organizer/server.test.ts new file mode 100644 index 0000000..b8c9f89 --- /dev/null +++ b/plugins/thread-organizer/server.test.ts @@ -0,0 +1,312 @@ +import { + createFakePluginHost, + makeThreadResponse, +} from "@bb/plugin-sdk/testing"; +import { describe, expect, it, vi } from "vitest"; + +import plugin from "./server.js"; + +const sections = [ + { id: "sec_bb", name: "bb" }, + { id: "sec_design", name: "Design" }, + { id: "sec_extensions", name: "Extensions" }, + { id: "sec_qa", name: "QA" }, + { id: "sec_writing", name: "Writing" }, +]; + +function promptEntry(text: string, createdAt = 1) { + return { + id: `prompt_${createdAt}`, + createdAt, + input: [{ type: "text" as const, text }], + }; +} + +function completedEvent(seq: number) { + return { + id: `event_${seq}`, + createdAt: seq, + data: { providerThreadId: null, status: "completed" as const }, + scope: { kind: "thread" as const }, + seq, + threadId: "thr_test", + type: "turn/completed" as const, + }; +} + +function createHarness(input?: { + mode?: "apply" | "observe"; + projectName?: string; + prompt?: string; + thread?: Parameters[0]; +}) { + const prompt = + input?.prompt ?? + "Create a bb plugin that automatically organizes new threads."; + let thread = makeThreadResponse({ + id: "thr_test", + projectId: "proj_test", + status: "starting", + title: null, + titleFallback: prompt, + ...input?.thread, + }); + const events: ReturnType[] = []; + const update = vi.fn( + async (args: { + sectionId?: string | null; + threadId: string; + title?: string | null; + }) => { + thread = makeThreadResponse({ + ...thread, + ...(Object.hasOwn(args, "sectionId") + ? { sectionId: args.sectionId ?? null } + : {}), + ...(Object.hasOwn(args, "title") + ? { title: args.title ?? null } + : {}), + updatedAt: thread.updatedAt + 1, + }); + return thread; + }, + ); + const host = createFakePluginHost({ + pluginId: "thread-organizer", + settings: { mode: input?.mode ?? "observe" }, + sdk: { + projects: { + get: async () => ({ + id: "proj_test", + name: input?.projectName ?? "Personal", + }), + }, + threadSections: { list: async () => sections }, + threads: { + events: { + wait: async (args: { afterSeq?: string }) => { + const after = Number(args.afterSeq ?? 0); + return events.find((event) => event.seq > after) ?? null; + }, + }, + get: async () => thread, + promptHistory: async () => [promptEntry(prompt)], + update, + }, + }, + }); + + return { + ...host, + addCompletedTurn(seq: number) { + events.push(completedEvent(seq)); + thread = makeThreadResponse({ ...thread, status: "idle" }); + }, + currentThread() { + return thread; + }, + setThread( + changes: Partial>, + ): void { + thread = makeThreadResponse({ ...thread, ...changes }); + }, + update, + }; +} + +describe("Thread Organizer plugin", () => { + it("registers a headless observe-mode lifecycle", async () => { + const { bb, harness } = createHarness(); + plugin(bb); + + expect(harness.inspection.registrations.settingsDescriptors).toMatchObject({ + mode: { default: "observe", options: ["observe", "apply"] }, + }); + expect(harness.inspection.registrations.threadEventHandlers).toMatchObject({ + "thread.active": 1, + "thread.archived": 1, + "thread.created": 1, + "thread.deleted": 1, + "thread.idle": 1, + }); + expect(harness.inspection.registrations.cli).toBeNull(); + expect(harness.inspection.registrations.rpcMethods).toEqual([]); + await harness.lifecycle.dispose(); + }); + + it("logs a recommendation without changing a thread in observe mode", async () => { + const { bb, harness, currentThread, update } = createHarness(); + plugin(bb); + + await harness.behavior.emitThreadEvent("thread.created", { + thread: currentThread(), + }); + + expect(update).not.toHaveBeenCalled(); + expect(harness.inspection.logEntries).toContainEqual( + expect.objectContaining({ + level: "info", + message: expect.stringContaining( + "mode=observe action=propose-section target=extensions", + ), + }), + ); + await harness.lifecycle.dispose(); + }); + + it("places a new unsectioned plugin thread in Extensions in apply mode", async () => { + const { bb, harness, currentThread, update } = createHarness({ + mode: "apply", + }); + plugin(bb); + + await harness.behavior.emitThreadEvent("thread.created", { + thread: currentThread(), + }); + + expect(update).toHaveBeenCalledWith({ + threadId: "thr_test", + sectionId: "sec_extensions", + }); + await harness.lifecycle.dispose(); + }); + + it("never changes an explicit creation-time section", async () => { + const { bb, harness, currentThread, update } = createHarness({ + mode: "apply", + thread: { sectionId: "sec_qa" }, + }); + plugin(bb); + + await harness.behavior.emitThreadEvent("thread.created", { + thread: currentThread(), + }); + + expect(update).not.toHaveBeenCalled(); + await harness.lifecycle.dispose(); + }); + + it("locks title and section management after manual overrides", async () => { + const organizer = createHarness({ mode: "apply" }); + plugin(organizer.bb); + await organizer.harness.behavior.emitThreadEvent("thread.created", { + thread: organizer.currentThread(), + }); + expect(organizer.currentThread().sectionId).toBe("sec_extensions"); + + organizer.setThread({ + sectionId: "sec_qa", + status: "active", + title: "My Manual Title", + }); + await organizer.harness.behavior.emitThreadEvent("thread.active", { + thread: organizer.currentThread(), + }); + + expect(organizer.update).toHaveBeenCalledTimes(1); + expect(organizer.harness.inspection.logEntries).toContainEqual( + expect.objectContaining({ + message: expect.stringContaining( + "action=manual-lock title=true section=true", + ), + }), + ); + await organizer.harness.lifecycle.dispose(); + }); + + it("repairs a missing title only after the first completed turn", async () => { + const organizer = createHarness({ + mode: "apply", + projectName: "Personal", + prompt: "Please fix the external file nav.", + }); + plugin(organizer.bb); + await organizer.harness.behavior.emitThreadEvent("thread.created", { + thread: organizer.currentThread(), + }); + expect(organizer.update).not.toHaveBeenCalled(); + + await organizer.harness.behavior.emitThreadEvent("thread.idle", { + lastAssistantText: null, + thread: organizer.currentThread(), + }); + expect(organizer.update).not.toHaveBeenCalled(); + + organizer.addCompletedTurn(10); + await organizer.harness.behavior.emitThreadEvent("thread.idle", { + lastAssistantText: "Done.", + thread: organizer.currentThread(), + }); + + expect(organizer.update).toHaveBeenCalledWith({ + threadId: "thr_test", + title: "Fix External File Nav", + }); + await organizer.harness.lifecycle.dispose(); + }); + + it("evaluates at turns 1 and 5, not every idle transition", async () => { + const organizer = createHarness({ mode: "observe" }); + plugin(organizer.bb); + await organizer.harness.behavior.emitThreadEvent("thread.created", { + thread: organizer.currentThread(), + }); + + for (let turn = 1; turn <= 5; turn += 1) { + organizer.addCompletedTurn(turn * 10); + await organizer.harness.behavior.emitThreadEvent("thread.idle", { + lastAssistantText: "Done.", + thread: organizer.currentThread(), + }); + } + + const turnProposals = organizer.harness.inspection.logEntries.filter( + ({ message }) => + message.includes("phase=turn") && + message.includes("action=propose-section"), + ); + expect(turnProposals).toHaveLength(2); + await organizer.harness.lifecycle.dispose(); + }); + + it("ignores hidden and plugin-originated workers", async () => { + const organizer = createHarness({ + mode: "apply", + thread: { originPluginId: "automations", visibility: "hidden" }, + }); + plugin(organizer.bb); + await organizer.harness.behavior.emitThreadEvent("thread.created", { + thread: organizer.currentThread(), + }); + + expect(organizer.update).not.toHaveBeenCalled(); + expect( + organizer.harness.inspection.sdk.callsTo("threads.get"), + ).toHaveLength(0); + await organizer.harness.lifecycle.dispose(); + }); + + it("forgets archived threads", async () => { + const organizer = createHarness({ mode: "observe" }); + plugin(organizer.bb); + await organizer.harness.behavior.emitThreadEvent("thread.created", { + thread: organizer.currentThread(), + }); + const callsBeforeArchive = + organizer.harness.inspection.sdk.callsTo("threads.get").length; + + organizer.setThread({ archivedAt: 10, status: "idle" }); + await organizer.harness.behavior.emitThreadEvent("thread.archived", { + thread: organizer.currentThread(), + }); + organizer.setThread({ archivedAt: null, status: "active" }); + await organizer.harness.behavior.emitThreadEvent("thread.active", { + thread: organizer.currentThread(), + }); + + expect( + organizer.harness.inspection.sdk.callsTo("threads.get"), + ).toHaveLength(callsBeforeArchive); + await organizer.harness.lifecycle.dispose(); + }); +}); diff --git a/plugins/thread-organizer/server.ts b/plugins/thread-organizer/server.ts new file mode 100644 index 0000000..c96ff98 --- /dev/null +++ b/plugins/thread-organizer/server.ts @@ -0,0 +1,514 @@ +import type { BbPluginApi } from "@bb/plugin-sdk"; + +import { + advanceEvaluationMilestone, + classifySection, + deriveTaskTitle, + isEligibleThread, + isSubstantiveText, + resolveSectionId, + type SectionClassification, +} from "./core.js"; + +const STATE_PREFIX = "thread:v1:"; +const NEW_SECTION_CONFIDENCE = 0.85; +const NEW_SECTION_MARGIN = 0.2; +const MOVE_SECTION_CONFIDENCE = 0.92; +const MOVE_SECTION_MARGIN = 0.25; +const TITLE_CONFIDENCE = 0.9; +const MAX_COMPLETED_EVENT_DRAIN = 100; + +type Thread = Awaited>; +type EvaluationPhase = "active" | "created" | "settings" | "turn"; + +interface ThreadState { + completedTurns: number; + createdAt: number; + hasAppliedSection: boolean; + hasAppliedTitle: boolean; + lastAppliedSectionId: string | null; + lastAppliedTitle: string | null; + lastCompletedSeq: number; + nextEvaluationTurn: number; + pendingSectionId: string | null; + pendingSectionStreak: number; + sectionLocked: boolean; + titleLocked: boolean; + version: 1; +} + +function stateKey(threadId: string): string { + return `${STATE_PREFIX}${threadId}`; +} + +function initialState(thread: Thread): ThreadState { + return { + completedTurns: 0, + createdAt: thread.createdAt, + hasAppliedSection: false, + hasAppliedTitle: false, + lastAppliedSectionId: null, + lastAppliedTitle: null, + lastCompletedSeq: 0, + nextEvaluationTurn: 1, + pendingSectionId: null, + pendingSectionStreak: 0, + sectionLocked: thread.sectionId !== null, + titleLocked: thread.title !== null, + version: 1, + }; +} + +function isThreadState(value: unknown): value is ThreadState { + if (typeof value !== "object" || value === null) return false; + const state = value as Partial; + return ( + state.version === 1 && + typeof state.completedTurns === "number" && + typeof state.createdAt === "number" && + typeof state.hasAppliedSection === "boolean" && + typeof state.hasAppliedTitle === "boolean" && + (typeof state.lastAppliedSectionId === "string" || + state.lastAppliedSectionId === null) && + (typeof state.lastAppliedTitle === "string" || + state.lastAppliedTitle === null) && + typeof state.lastCompletedSeq === "number" && + typeof state.nextEvaluationTurn === "number" && + (typeof state.pendingSectionId === "string" || + state.pendingSectionId === null) && + typeof state.pendingSectionStreak === "number" && + typeof state.sectionLocked === "boolean" && + typeof state.titleLocked === "boolean" + ); +} + +function syncManualLocks(state: ThreadState, thread: Thread): boolean { + let changed = false; + if (!state.titleLocked) { + const externalTitle = + state.hasAppliedTitle + ? thread.title !== state.lastAppliedTitle + : thread.title !== null; + if (externalTitle) { + state.titleLocked = true; + changed = true; + } + } + if (!state.sectionLocked) { + const externalSection = + state.hasAppliedSection + ? thread.sectionId !== state.lastAppliedSectionId + : thread.sectionId !== null; + if (externalSection) { + state.sectionLocked = true; + changed = true; + } + } + return changed; +} + +function promptTexts( + history: Awaited< + ReturnType + >, +): string[] { + return [...history] + .sort((left, right) => left.createdAt - right.createdAt) + .flatMap((entry) => + entry.input.flatMap((item) => + item.type === "text" && item.visibility !== "agent-only" + ? [item.text] + : [], + ), + ); +} + +function classificationSummary(decision: SectionClassification): string { + return [ + `target=${decision.target}`, + `confidence=${decision.confidence.toFixed(2)}`, + `margin=${decision.margin.toFixed(2)}`, + `reason=${decision.reasons.join(",")}`, + ].join(" "); +} + +function delay(milliseconds: number): Promise { + return new Promise((resolve) => setTimeout(resolve, milliseconds)); +} + +export default function plugin(bb: BbPluginApi): void { + const settings = bb.settings.define({ + mode: { + type: "select", + label: "Mode", + description: + "Observe logs recommendations without changing threads. Apply enables high-confidence updates.", + options: ["observe", "apply"], + default: "observe", + }, + }); + const queues = new Map>(); + let disposed = false; + + async function readState(threadId: string): Promise { + const stored = await bb.storage.kv.get(stateKey(threadId)); + if (stored === undefined) return null; + if (isThreadState(stored)) return stored; + bb.log.warn(`thread=${threadId} action=ignore-invalid-state`); + return null; + } + + async function saveState( + threadId: string, + state: ThreadState, + ): Promise { + await bb.storage.kv.set(stateKey(threadId), state); + } + + function enqueue(threadId: string, work: () => Promise): Promise { + const previous = queues.get(threadId) ?? Promise.resolve(); + const current = previous + .catch(() => undefined) + .then(async () => { + if (!disposed) await work(); + }) + .catch((error: unknown) => { + const message = error instanceof Error ? error.message : String(error); + bb.log.error(`thread=${threadId} action=queue-failed error=${message}`); + }) + .finally(() => { + if (queues.get(threadId) === current) queues.delete(threadId); + }); + queues.set(threadId, current); + return current; + } + + async function loadContextTexts( + thread: Thread, + attempts: number, + ): Promise { + let loaded: string[] = []; + for (let attempt = 0; attempt < attempts; attempt += 1) { + try { + loaded = promptTexts( + await bb.sdk.threads.promptHistory({ + threadId: thread.id, + limit: "6", + }), + ); + } catch (error: unknown) { + const message = error instanceof Error ? error.message : String(error); + bb.log.debug( + `thread=${thread.id} action=prompt-history-unavailable attempt=${attempt + 1} error=${message}`, + ); + } + if (loaded.some(isSubstantiveText) || attempt === attempts - 1) break; + await delay(attempt === 0 ? 150 : 600); + } + return loaded; + } + + async function applySection( + thread: Thread, + state: ThreadState, + phase: EvaluationPhase, + decision: SectionClassification, + targetSectionId: string, + mode: string, + ): Promise { + if (state.sectionLocked) return; + + const movingManagedSection = thread.sectionId !== null; + const minimumConfidence = movingManagedSection + ? MOVE_SECTION_CONFIDENCE + : NEW_SECTION_CONFIDENCE; + const minimumMargin = movingManagedSection + ? MOVE_SECTION_MARGIN + : NEW_SECTION_MARGIN; + if ( + decision.confidence < minimumConfidence || + decision.margin < minimumMargin + ) { + state.pendingSectionId = null; + state.pendingSectionStreak = 0; + return; + } + if (thread.sectionId === targetSectionId) { + state.pendingSectionId = null; + state.pendingSectionStreak = 0; + return; + } + + if (movingManagedSection) { + if (!state.hasAppliedSection || phase !== "turn") return; + if (state.pendingSectionId === targetSectionId) { + state.pendingSectionStreak += 1; + } else { + state.pendingSectionId = targetSectionId; + state.pendingSectionStreak = 1; + } + if (state.pendingSectionStreak < 2) return; + } + + if (mode !== "apply") { + bb.log.info( + `thread=${thread.id} phase=${phase} mode=observe action=propose-section ${classificationSummary(decision)}`, + ); + return; + } + + const fresh = (await bb.sdk.threads.get({ + threadId: thread.id, + })) as Thread; + syncManualLocks(state, fresh); + if ( + state.sectionLocked || + !isEligibleThread(fresh) || + fresh.sectionId !== thread.sectionId + ) { + return; + } + const updated = await bb.sdk.threads.update({ + threadId: thread.id, + sectionId: targetSectionId, + }); + state.hasAppliedSection = true; + state.lastAppliedSectionId = updated.sectionId; + state.pendingSectionId = null; + state.pendingSectionStreak = 0; + bb.log.info( + `thread=${thread.id} phase=${phase} mode=apply action=section-updated ${classificationSummary(decision)}`, + ); + } + + async function applyTitle( + thread: Thread, + state: ThreadState, + phase: EvaluationPhase, + texts: string[], + mode: string, + ): Promise { + if (phase !== "turn" || state.titleLocked || thread.title !== null) return; + const source = + texts.find(isSubstantiveText) ?? thread.titleFallback ?? undefined; + if (source === undefined) return; + const candidate = deriveTaskTitle(source); + if (candidate === null || candidate.confidence < TITLE_CONFIDENCE) return; + + if (mode !== "apply") { + bb.log.info( + `thread=${thread.id} phase=${phase} mode=observe action=propose-title confidence=${candidate.confidence.toFixed(2)} title=${JSON.stringify(candidate.title)}`, + ); + return; + } + + const fresh = (await bb.sdk.threads.get({ + threadId: thread.id, + })) as Thread; + syncManualLocks(state, fresh); + if (state.titleLocked || !isEligibleThread(fresh) || fresh.title !== null) { + return; + } + const updated = await bb.sdk.threads.update({ + threadId: thread.id, + title: candidate.title, + }); + state.hasAppliedTitle = true; + state.lastAppliedTitle = updated.title; + bb.log.info( + `thread=${thread.id} phase=${phase} mode=apply action=title-updated confidence=${candidate.confidence.toFixed(2)} title=${JSON.stringify(candidate.title)}`, + ); + } + + async function evaluate( + threadId: string, + phase: EvaluationPhase, + ): Promise { + const state = await readState(threadId); + if (state === null) return; + const thread = (await bb.sdk.threads.get({ threadId })) as Thread; + const locksChanged = syncManualLocks(state, thread); + if (locksChanged) { + bb.log.info( + `thread=${threadId} action=manual-lock title=${state.titleLocked} section=${state.sectionLocked}`, + ); + } + if (thread.archivedAt !== null || thread.deletedAt !== null) { + await bb.storage.kv.delete(stateKey(threadId)); + return; + } + if (!isEligibleThread(thread)) { + await saveState(threadId, state); + return; + } + + const attempts = phase === "active" ? 3 : 1; + const historyTexts = await loadContextTexts(thread, attempts); + const texts = [ + ...(thread.title === null ? [] : [thread.title]), + ...(thread.titleFallback === null ? [] : [thread.titleFallback]), + ...historyTexts, + ]; + const { mode } = await settings.get(); + + if (!state.sectionLocked) { + try { + const project = await bb.sdk.projects.get({ + projectId: thread.projectId, + }); + const decision = classifySection({ + projectName: project.name, + texts, + }); + if (decision !== null) { + const sectionId = resolveSectionId( + await bb.sdk.threadSections.list(), + decision.target, + ); + if (sectionId === null) { + bb.log.warn( + `thread=${threadId} phase=${phase} action=section-unavailable target=${decision.target}`, + ); + } else { + await applySection( + thread, + state, + phase, + decision, + sectionId, + mode, + ); + } + } else { + state.pendingSectionId = null; + state.pendingSectionStreak = 0; + } + } catch (error: unknown) { + const message = error instanceof Error ? error.message : String(error); + bb.log.warn( + `thread=${threadId} phase=${phase} action=section-evaluation-failed error=${message}`, + ); + } + } + + try { + await applyTitle(thread, state, phase, historyTexts, mode); + } catch (error: unknown) { + const message = error instanceof Error ? error.message : String(error); + bb.log.warn( + `thread=${threadId} phase=${phase} action=title-evaluation-failed error=${message}`, + ); + } + await saveState(threadId, state); + } + + async function consumeCompletedTurns( + threadId: string, + state: ThreadState, + ): Promise { + let drained = 0; + while (drained < MAX_COMPLETED_EVENT_DRAIN) { + const event = await bb.sdk.threads.events.wait({ + threadId, + type: "turn/completed", + waitMs: "1", + ...(state.lastCompletedSeq === 0 + ? {} + : { afterSeq: String(state.lastCompletedSeq) }), + }); + if (event === null) break; + state.lastCompletedSeq = event.seq; + if ( + event.type === "turn/completed" && + event.data.status === "completed" + ) { + state.completedTurns += 1; + } + drained += 1; + } + if (drained === MAX_COMPLETED_EVENT_DRAIN) { + bb.log.warn( + `thread=${threadId} action=turn-drain-capped limit=${MAX_COMPLETED_EVENT_DRAIN}`, + ); + } + } + + bb.events.on("thread.created", ({ thread }) => + enqueue(thread.id, async () => { + if (!isEligibleThread(thread)) return; + if ((await readState(thread.id)) !== null) return; + await saveState(thread.id, initialState(thread)); + await evaluate(thread.id, "created"); + }), + ); + + bb.events.on("thread.active", ({ thread }) => + enqueue(thread.id, async () => { + if ((await readState(thread.id)) === null) return; + await evaluate(thread.id, "active"); + }), + ); + + bb.events.on("thread.idle", ({ thread }) => + enqueue(thread.id, async () => { + const state = await readState(thread.id); + if (state === null) return; + try { + await consumeCompletedTurns(thread.id, state); + } catch (error: unknown) { + const message = error instanceof Error ? error.message : String(error); + bb.log.warn( + `thread=${thread.id} action=turn-count-failed error=${message}`, + ); + } + const due = state.completedTurns >= state.nextEvaluationTurn; + if (due) { + state.nextEvaluationTurn = advanceEvaluationMilestone( + state.nextEvaluationTurn, + state.completedTurns, + ); + } + await saveState(thread.id, state); + if (due) await evaluate(thread.id, "turn"); + }), + ); + + const forget = (threadId: string) => + enqueue(threadId, async () => { + await bb.storage.kv.delete(stateKey(threadId)); + }); + bb.events.on("thread.archived", ({ thread }) => forget(thread.id)); + bb.events.on("thread.deleted", ({ thread }) => forget(thread.id)); + + settings.onChange((next, previous) => { + if (next.mode === previous.mode) return; + bb.log.info(`action=mode-changed previous=${previous.mode} next=${next.mode}`); + if (next.mode !== "apply") return; + void bb.storage.kv + .list(STATE_PREFIX) + .then((keys) => + Promise.all( + keys.map((key) => + enqueue(key.slice(STATE_PREFIX.length), () => + evaluate(key.slice(STATE_PREFIX.length), "settings"), + ), + ), + ), + ) + .catch((error: unknown) => { + const message = error instanceof Error ? error.message : String(error); + bb.log.error(`action=apply-mode-evaluation-failed error=${message}`); + }); + }); + + bb.onDispose(() => { + disposed = true; + }); + void settings + .get() + .then(({ mode }) => bb.log.info(`Thread Organizer loaded mode=${mode}`)) + .catch((error: unknown) => { + const message = error instanceof Error ? error.message : String(error); + bb.log.warn(`action=mode-read-failed error=${message}`); + }); +} diff --git a/plugins/thread-organizer/tsconfig.json b/plugins/thread-organizer/tsconfig.json new file mode 100644 index 0000000..db529e7 --- /dev/null +++ b/plugins/thread-organizer/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": [ + "ES2022" + ], + "module": "ESNext", + "moduleResolution": "Bundler", + "baseUrl": ".", + "paths": { + "@bb/plugin-sdk": [ + "./types/bb-plugin-sdk.d.ts" + ], + "@bb/plugin-sdk/app": [ + "./types/bb-plugin-sdk-app.d.ts" + ] + }, + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "types": [ + "node", + "vitest/globals" + ] + }, + "include": [ + "*.ts" + ] +} diff --git a/plugins/thread-organizer/types/bb-plugin-sdk-app.d.ts b/plugins/thread-organizer/types/bb-plugin-sdk-app.d.ts new file mode 100644 index 0000000..22cf8e7 --- /dev/null +++ b/plugins/thread-organizer/types/bb-plugin-sdk-app.d.ts @@ -0,0 +1,794 @@ +// Portable type declarations for `@bb/plugin-sdk`. Unpublished BB +// workspace contracts are flattened; public subpaths may reuse the +// package root without requiring any other @bb/* package. +// +// Confused by the API, or need a symbol that isn't here? Clone the BB repo +// and read the real source: https://github.com/ymichael/bb + +import * as react from 'react'; +import { ComponentType, ReactNode } from 'react'; + +/** A JSON-safe path segment reported by a Standard Schema validation issue. */ +type PluginRpcIssuePathSegment = string | number; +/** Validator-neutral validation detail carried by an RPC error envelope. */ +interface PluginRpcValidationIssue { + message: string; + path?: PluginRpcIssuePathSegment[]; +} +/** Stable wire error categories for plugin RPC. */ +type PluginRpcErrorCode = "invalid_json" | "invalid_input" | "handler_error" | "invalid_output" | "non_json_result" | "unknown_method"; +/** Structured RPC failure returned as `{ ok: false, error }`. */ +interface PluginRpcError { + code: PluginRpcErrorCode; + message: string; + issues?: PluginRpcValidationIssue[]; +} +/** + * The validator-neutral subset of Standard Schema v1 used by plugin RPC. + * Zod 4 schemas implement this interface directly; other validators can do + * the same without becoming part of BB's public protocol. + */ +interface StandardSchemaV1 { + readonly "~standard": { + readonly version: 1; + readonly vendor: string; + readonly validate: (value: unknown) => StandardSchemaV1Result | Promise>; + readonly types?: { + readonly input: Input; + readonly output: Output; + }; + }; +} +type StandardSchemaV1Result = { + readonly value: Output; + readonly issues?: undefined; +} | { + readonly issues: readonly StandardSchemaV1Issue[]; +}; +interface StandardSchemaV1Issue { + readonly message: string; + readonly path?: PropertyKey | readonly (PropertyKey | { + readonly key: PropertyKey; + })[]; +} +type StandardSchemaV1InferInput = NonNullable["input"]; +type StandardSchemaV1InferOutput = NonNullable["output"]; +interface PluginRpcMethodContract { + readonly input: InputSchema; + readonly output: OutputSchema; +} +type PluginRpcContract = Readonly>; +type PluginRpcHandlers = { + [Method in keyof Contract]: (input: StandardSchemaV1InferOutput) => StandardSchemaV1InferInput | Promise>; +}; +type PluginRpcCallInput = StandardSchemaV1InferInput; +type PluginRpcCallArgs = null extends PluginRpcCallInput ? [input?: PluginRpcCallInput] : [input: PluginRpcCallInput]; +type PluginRpcResult = StandardSchemaV1InferOutput; + +/** + * A value that survives a JSON round trip without coercion or data loss. + * + * Host boundaries still validate values at runtime because TypeScript cannot + * exclude non-finite numbers and plugin bundles can bypass static types. + */ +type JsonValue = string | number | boolean | null | JsonValue[] | { + [key: string]: JsonValue; +}; + +/** + * The `@bb/plugin-sdk/app` contract (plugin design §5.2) — pure types with no + * side effects. The BB app imports these to keep its real implementation in + * sync (`satisfies PluginSdkApp`). Plugin authors import the same shapes through + * `@bb/plugin-sdk/app`. + * + * Per-slot props are versioned contracts: additive-only within an SDK major. + */ +/** Props passed to a `homepageSection` component. */ +interface PluginHomepageSectionProps { + /** Project in view on the compose surface; null when none is selected. */ + projectId: string | null; +} +/** + * Props passed to a `settingsSection` component. + * + * Deliberately empty in V1; versioned additive like the other slot props. + */ +interface PluginSettingsSectionProps { +} +/** Props passed to a `navPanel` component (it owns its whole route). */ +interface PluginNavPanelProps { + /** + * The route remainder after the panel root, "" at the root. The panel's + * route is `/plugins///*`, so a deep link like + * `/plugins/notes/notes/work/ideas.md` renders the panel with + * `subPath: "work/ideas.md"`. Navigate within the panel via + * `useBbNavigate().toPluginPanel(path, { subPath })` — browser + * back/forward then walks panel-internal history. + */ + subPath: string; +} +/** Props passed to a panel tab opened by a `threadPanelAction`. */ +interface PluginThreadPanelProps { + threadId: string; + /** + * The JSON value the action's `openPanel` call passed (round-tripped + * through persistence, so the tab restores across reloads); null when the + * action opened the panel without params. + */ + params: JsonValue | null; +} +interface PluginPendingInteractionView { + id: string; + threadId: string; + title: string; + payload: JsonValue; + createdAt: number; + expiresAt: number | null; +} +interface PluginPendingInteractionProps { + interaction: PluginPendingInteractionView; + submit(value: JsonValue): Promise; + cancel(): Promise; +} +/** + * Props for a `sidebarFooterAction` — host-rendered (no plugin component). + * Deliberately empty; the registration's `run` carries the behavior. + */ +interface PluginSidebarFooterActionProps { +} +/** + * Where a file being opened by a `fileOpener` lives. `path` semantics follow + * the source: workspace paths are relative to the environment's worktree, + * thread-storage paths are relative to the thread's storage root, host paths + * are absolute on the thread's host. + */ +interface PluginFileOpenerSource { + kind: "workspace" | "host" | "thread-storage"; + threadId: string | null; + environmentId: string | null; + projectId: string | null; +} +/** Props passed to a `fileOpener` component (rendered as a panel file tab). */ +interface PluginFileOpenerProps { + path: string; + source: PluginFileOpenerSource; +} +/** + * Message context passed to a `messageDirective` component — the assistant + * (or nested agent) message that contained the directive. + */ +interface PluginMessageDirectiveMessage { + id: string; + threadId: string; + turnId: string | null; + projectId: string | null; +} +/** + * Open a worktree-relative file in the host's workspace file viewer. Returns + * true when the host accepted the path; false when the path is invalid or the + * viewer declined it. + */ +type PluginMessageDirectiveOpenWorkspaceFile = (path: string) => boolean; +/** + * Props passed to a `messageDirective` component. Attributes are untrusted + * strings parsed from the directive; the plugin validates its own fields. + */ +interface PluginMessageDirectiveProps { + /** Parsed, untrusted directive attributes (e.g. `{ file: "demo.html" }`). */ + attributes: Readonly>; + /** Original directive source text (useful for diagnostics / crash fallback). */ + source: string; + message: PluginMessageDirectiveMessage; + /** + * Opens a worktree-relative file in the host's workspace file viewer. Null + * when the message surface has no workspace viewer available. + */ + openWorkspaceFile: PluginMessageDirectiveOpenWorkspaceFile | null; +} +interface PluginHomepageSectionRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + title: string; + component: ComponentType; +} +interface PluginSettingsSectionRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Optional host-rendered section heading. */ + title?: string; + /** + * Optional one-line host-rendered subheading under `title`, in the built-in + * SettingsSection idiom (ignored when `title` is absent). + */ + description?: string; + component: ComponentType; +} +interface PluginNavPanelRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + title: string; + /** Icon hint (BB icon name); unknown names fall back to a generic icon. */ + icon: string; + /** URL segment under `/plugins//`; letters, digits, `-`, `_`. */ + path: string; + component: ComponentType; + /** + * Optional component rendered on the right side of the shared title bar + * (e.g. a sync button or a count). Contained separately from the body: a + * throwing headerContent is hidden without breaking the title bar. + */ + headerContent?: ComponentType; +} +/** Context handed to a `threadPanelAction`'s `run`. */ +interface PluginThreadPanelActionContext { + /** The thread whose panel launcher invoked the action. */ + threadId: string; + /** + * Open a tab in the thread's side panel rendering this action's + * `component`. `title` labels the tab (default: the action's `title`); + * `params` must be JSON-serializable — it is persisted with the tab and + * reaches the component as its `params` prop. Opening with params + * identical to an already-open tab of this action focuses that tab + * (updating its title) instead of duplicating it. May be called more than + * once (different params ⇒ multiple tabs) or not at all. + */ + openPanel(options?: { + title?: string; + params?: JsonValue; + }): void; +} +interface PluginThreadPanelActionRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Label of the action row in the panel's new-tab launcher. */ + title: string; + /** + * Icon hint (BB icon name) used when the plugin ships no logo; the + * launcher row and opened tabs prefer the plugin's logo. + */ + icon?: string; + /** Rendered inside every panel tab this action opens. */ + component: ComponentType; + /** + * How the host frames the tab content. "padded" (default) wraps the + * component in the panel's scroll container with standard padding — + * right for document-like content. "flush" gives the component the full + * tab area (no padding, definite height, no host scrolling) — right for + * app-like content that manages its own layout, such as + * `experimental_ThreadChat`. + */ + layout?: "padded" | "flush"; + /** + * Runs when the user activates the action: call your RPC methods, show a + * toast, and/or open panel tabs via `context.openPanel`. Omitted = + * immediately open a panel tab with defaults. Errors (sync or async) are + * contained and logged; they never break the launcher. + */ + run?(context: PluginThreadPanelActionContext): void | Promise; +} +interface PluginPendingInteractionRegistration { + /** Matches `rendererId` passed to `bb.ui.requestInput`. */ + id: string; + component: ComponentType; +} +/** Context handed to a `sidebarFooterAction`'s `run`. */ +interface PluginSidebarFooterActionContext { + /** + * Navigate to this plugin's Settings detail page + * (`/settings/plugins/`), where declarative settings and + * `settingsSection` slots render. + */ + openSettings(): void; +} +/** + * An icon button in the app sidebar footer (next to Settings / bug report). + * Host-rendered for consistent chrome — plugins supply icon, label, and + * `run` behavior only. + */ +interface PluginSidebarFooterActionRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Tooltip and accessible label for the icon button. */ + title: string; + /** Icon hint (BB icon name); unknown names fall back to a generic icon. */ + icon: string; + /** + * Runs when the user activates the action (e.g. call `openSettings()`, + * open a panel via other surfaces, toast). Errors (sync or async) are + * contained and logged; they never break the sidebar. + */ + run(context: PluginSidebarFooterActionContext): void | Promise; +} +/** + * Register this plugin as a viewer/editor for file extensions. The user + * picks (and can set as default) an opener per extension via the file tab's + * "Open with" menu; matching files opened in the panel then render + * `component` in a plugin tab instead of the built-in preview. Applies to + * working-tree, host, and thread-storage files — never to git-ref snapshots + * (diff views always use the built-in preview). The built-in preview stays + * one menu click away, and a missing/disabled opener falls back to it. + */ +interface PluginFileOpenerRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Label in the "Open with" menu (e.g. "Notes editor"). */ + title: string; + /** Lowercase extensions without the dot (e.g. ["md", "mdx"]). */ + extensions: readonly string[]; + component: ComponentType; +} +/** + * Register a leaf message directive rendered inside assistant (and nested + * agent) message Markdown. `id` is the directive name: `inline-vis` matches + * `::inline-vis{file="demo.html"}`. + */ +interface PluginMessageDirectiveRegistration { + /** + * The directive name. Lowercase kebab-case beginning with a letter. + */ + id: string; + component: ComponentType; +} +/** + * A narrow, stable reference to one rendered chat message — NOT an internal + * timeline row. `sourceSeqEnd` is the last source event sequence the message + * covers, the anchor the server accepts for provider-history forks. + */ +interface ThreadChatMessageReference { + id: string; + threadId: string; + role: "user" | "assistant"; + /** Visible text of the message. */ + text: string; + sourceSeqEnd: number; +} +interface PluginMessageActionThreadPanelOptions { + /** A `threadPanelAction` id registered by this same plugin. */ + actionId: string; + title?: string; + params?: JsonValue; +} +/** Context handed to a `messageAction`'s `run`. */ +interface PluginMessageActionContext { + /** The thread whose timeline surfaced the action. */ + threadId: string; + message: ThreadChatMessageReference; + /** + * Present only when the action was invoked from the text-selection menu; + * the exact text the user highlighted inside `message`. + */ + selectedText?: string; + /** + * Open one of this plugin's `threadPanelAction` components in the current + * thread's side panel — the registration-callback equivalent of + * `useBbNavigate().experimental_openThreadPanel`. Returns true when the host + * accepted (the action id exists and the surface has a panel); false + * otherwise. + */ + openPanel(options: PluginMessageActionThreadPanelOptions): boolean; +} +/** + * An action on chat messages: an icon button in the per-message action bar + * (user and assistant messages) and an entry in the assistant-message + * text-selection menu. Host-rendered chrome — the plugin supplies title, + * icon hint, and `run` behavior only. + */ +interface PluginMessageActionRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Tooltip / menu label for the action. */ + title: string; + /** Icon hint (BB icon name); unknown names fall back to a generic icon. */ + icon?: string; + /** + * Runs when the user activates the action. Errors (sync or async) are + * contained and logged; they never break the timeline. + */ + run(context: PluginMessageActionContext): void | Promise; +} +interface PluginAppSlots { + homepageSection(registration: PluginHomepageSectionRegistration): void; + settingsSection(registration: PluginSettingsSectionRegistration): void; + navPanel(registration: PluginNavPanelRegistration): void; + threadPanelAction(registration: PluginThreadPanelActionRegistration): void; + pendingInteraction(registration: PluginPendingInteractionRegistration): void; + sidebarFooterAction(registration: PluginSidebarFooterActionRegistration): void; + fileOpener(registration: PluginFileOpenerRegistration): void; + messageDirective(registration: PluginMessageDirectiveRegistration): void; + experimental_messageAction(registration: PluginMessageActionRegistration): void; +} +interface PluginAppComposer { + customize(registration: ComposerCustomization): void; +} +/** Stable lifecycle values for one content-script instance in one bb client. */ +interface PluginContentScriptContext { + /** The id of the plugin that owns this script. */ + readonly pluginId: string; + /** Monotonic per-client generation, starting at 1. */ + readonly generation: number; + /** Aborted before cleanup begins on replacement, deactivation, or teardown. */ + readonly signal: AbortSignal; +} +/** Cleanup returned by a frontend content script. */ +type PluginContentScriptDisposer = () => void | Promise; +/** + * Trusted same-origin JavaScript/TypeScript mounted once per active frontend + * generation in each bb app window or browser tab. + */ +interface PluginContentScriptRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** + * Install behavior into the bb app shell. The host awaits a returned + * promise, contains failures, and calls the returned disposer exactly once. + */ + mount(context: PluginContentScriptContext): void | PluginContentScriptDisposer | Promise; +} +/** Experimental lifecycle surface for trusted frontend content scripts. */ +interface PluginAppContentScripts { + register(registration: PluginContentScriptRegistration): void; +} +interface PluginAppBuilder { + slots: PluginAppSlots; + composer: PluginAppComposer; + experimental_contentScripts: PluginAppContentScripts; +} +type PluginAppSetup = (app: PluginAppBuilder) => void; +/** + * The opaque product of `definePluginApp` — a plugin's `app.tsx` default + * export. The host re-runs `setup` against a fresh collector on every + * (re)interpretation, replacing that plugin's registrations wholesale. + */ +interface PluginAppDefinition { + /** Brand the host checks before interpreting a bundle's default export. */ + readonly __bbPluginApp: true; + readonly setup: PluginAppSetup; +} +interface PluginRpcClient { + /** + * Invoke one of the plugin's `bb.rpc` methods (POST + * /api/v1/plugins/<id>/rpc/<method>). Resolves with the method's + * inferred output; rejects with an `Error` carrying the server's message, + * stable `code`, and validation `issues` when present. + */ + call>(method: Method, ...args: PluginRpcCallArgs): Promise>; +} +interface PluginSettingsState { + /** + * Effective non-secret setting values (secret settings are excluded — + * read them server-side). Undefined while loading or unavailable. + */ + values: Record | undefined; + isLoading: boolean; +} +/** State of the app's shared realtime connection to the bb server. */ +type PluginRealtimeConnectionState = "connecting" | "connected" | "reconnecting"; +/** Where `useComposer()` writes. */ +type PluginComposerScope = { + kind: "thread"; + threadId: string; +} | { + kind: "queued-message"; + threadId: string; + queuedMessageId: string; +} | { + kind: "side-chat"; + projectId: string; + parentThreadId: string; + tabId: string; + childThreadId: string | null; +} | { + kind: "new-thread"; + /** Root compose's effective selected project; null only while unresolved. */ + projectId: string | null; +}; +/** One plugin-owned composer customization registration. */ +interface ComposerCustomization { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Composer kinds where this customization is active; omit for all kinds. */ + scopes?: readonly PluginComposerScope["kind"][]; + actions?: readonly { + id: string; + component: ComponentType; + }[]; + banners?: readonly { + id: string; + /** Host chrome around the banner. Defaults to `"card"`. */ + chrome?: "card" | "bare"; + component: ComponentType; + }[]; + plusMenu?: readonly ComposerPlusMenuItem[]; + richText?: ComposerRichTextSpec; +} +/** Host-rendered menu row in the composer's `+` menu. */ +interface ComposerPlusMenuItem { + id: string; + label: string; + /** BB icon name; unknown names fall back to the generic plugin icon. */ + icon?: string; + /** Accessible description for the host-rendered row. */ + description?: string; + disabled?: boolean | ((view: ComposerView) => boolean); + run(context: { + composer: PluginComposerApi; + view: ComposerView; + }): void | Promise; +} +/** Reactive read-side of the composer a plugin surface is mounted in. */ +interface ComposerView { + scope: PluginComposerScope; + layout: "expanded" | "compact" | "zen"; + draft: { + text: string; + isEmpty: boolean; + attachmentCount: number; + }; + run: { + isRunning: boolean; + isSubmitting: boolean; + }; +} +interface ComposerRichTextSpec { + /** Content-derived paint: match ranges receive `className`; text is never mutated. */ + effects?: readonly { + id: string; + /** Plain-text offsets into the current structured draft. */ + match(text: string): readonly { + from: number; + to: number; + }[]; + className: string; + }[]; + /** Debounced, read-only observation of the structured draft. */ + onDraftChange?(draft: ComposerStructuredDraft, view: ComposerView): void; +} +interface ComposerStructuredDraft { + text: string; + mentions: readonly { + from: number; + to: number; + provider: string; + id: string; + label: string; + }[]; +} +/** Host-rendered paint applied to the editable composer text. */ +interface PluginComposerTextEffect { + className: string; +} +/** Host-rendered status that temporarily replaces a thread's draft glyph. */ +interface PluginComposerThreadRowStatus { + /** BB icon-name hint; unknown names fall back to the generic plugin icon. */ + icon: string; + /** Accessible label for the status glyph. */ + label: string; + /** Semantic host color for the status glyph. Defaults to the neutral tone. */ + tone?: "default" | "success"; +} +/** An @-mention pill bound to one of the calling plugin's mention providers. */ +interface PluginComposerMention { + /** Mention provider id registered by THIS plugin via `bb.ui.registerMentionProvider`. */ + provider: string; + /** Item id your provider's `resolve` will receive at send time. */ + id: string; + /** Pill text shown in the composer. */ + label: string; +} +/** + * Programmatic access to the chat composer draft — the same shared draft the + * built-in "Add to chat" affordances (file preview, diff, terminal selections) + * write to. While a queued message is being edited, writes land in that + * message's inline editor. In a side chat, writes land in the visible side-chat + * draft. Otherwise, inside a thread context writes land in that thread's draft; + * anywhere else (nav panel, homepage section) they seed the new-thread composer + * draft, which persists until the user sends or clears it. + */ +interface PluginComposerApi { + scope: PluginComposerScope; + /** Current plain text for this composer scope. */ + readonly text: string; + /** + * Replace the draft's plain text. Attachments are preserved. Inline mentions + * outside the changed range are preserved and rebased; mentions overlapped + * by the replacement are removed because their text representation changed. + */ + setText(next: string): void; + /** + * Replace the draft's plain text from the latest committed value. Uses the + * same structured-state reconciliation as `setText`. + */ + updateText(updater: (current: string) => string): void; + /** Clear plain text without clearing independently attached files. */ + clear(): void; + /** + * Apply a host-rendered effect to this composer's editable text, or clear it. + * Effects are scoped to the calling plugin and automatically clear when the + * slot unmounts or its composer scope changes. + */ + setTextEffect(effect: PluginComposerTextEffect | null): void; + /** + * Lock or unlock editing for this composer. Locks are scoped to the calling + * plugin and automatically release when the slot unmounts or its composer + * scope changes. + */ + setInputLock(locked: boolean): void; + /** + * Replace this composer's thread-row draft glyph with a host-rendered status, + * or clear it. New-thread composers have no row, so calls are a no-op. + * Side-chat and queued side-chat scopes decorate the visible parent-thread + * row. Status is scoped to the calling plugin and automatically clears when + * the slot unmounts or its composer scope changes. + */ + setThreadRowStatus(status: PluginComposerThreadRowStatus | null): void; + /** + * Append text to the draft as a `> ` blockquote block and focus the + * composer. Blank text is a no-op. This is the "reference this selection + * in chat" primitive. + */ + addQuote(text: string): void; + /** + * Insert an @-mention pill that resolves through this plugin's mention + * provider at send time — the durable way to reference an entity whose + * content should be fetched fresh when the message is sent. + */ + insertMention(mention: PluginComposerMention): void; + /** Focus the composer caret at the end of the draft. */ + focus(): void; +} +/** + * A consumer-supplied action on the messages of one `ThreadChat` instance, + * rendered in the embedded timeline's per-message action bar alongside the + * native and slot-registered actions. Unlike the `messageAction` slot this is + * scoped to the rendering component, not registered globally. + */ +interface ThreadChatMessageAction { + /** Unique within this ThreadChat instance; letters, digits, `-`, `_`. */ + id: string; + /** Tooltip / menu label for the action. */ + title: string; + /** Icon hint (BB icon name); unknown names fall back to a generic icon. */ + icon?: string; + /** + * Message roles the action applies to. Omitted = both user and assistant + * messages. + */ + roles?: readonly ("user" | "assistant")[]; + /** + * Runs when the user activates the action. Errors (sync or async) are + * contained and logged; they never break the timeline. + */ + run(message: ThreadChatMessageReference): void | Promise; +} +/** + * Props of the host-owned `ThreadChat` component — one thread's chat + * (timeline, and for the composer variants the full send/queue/draft + * engine), rendered by the BB app inside a plugin slot. This is the + * deliberate exception to the no-host-components rule (§5.5): a stable + * product capability, not a UI kit. Versioned additive like slot props; + * internal timeline rows, query hooks, and prompt-box configuration are + * deliberately not exposed. + */ +interface ThreadChatProps { + threadId: string; + /** + * "full" (default) is the page presentation (centered reading width); + * "compact" is the side-panel presentation; "timeline" renders the + * transcript without a composer. + */ + variant?: "full" | "compact" | "timeline"; + /** + * "contained" (default) fills and scrolls inside a bounded parent; + * "document" grows with its content and defers scrolling to the page. + */ + layout?: "contained" | "document"; + /** Bump to focus the composer (ignored by `variant: "timeline"`). */ + focusRequest?: number; + className?: string; + /** Rendered above the conversation, scrolling with it. */ + leadingContent?: ReactNode; + /** + * Actions rendered in this instance's per-message action bar (see + * {@link ThreadChatMessageAction}). + */ + messageActions?: readonly ThreadChatMessageAction[]; +} +/** + * Props of the host-owned `Markdown` component — bb's chat message renderer + * (the same typography, spacing, and code styling as timeline messages). + * Use it wherever plugin UI quotes or previews message content so it reads + * like the rest of the chat. Like `ThreadChat`, this is a stable product + * capability, not a UI kit; renderer internals stay private. + */ +interface MarkdownProps { + /** Markdown source, rendered exactly like a chat message body. */ + content: string; + className?: string; +} +/** Current app selection, derived from the route. */ +interface BbContext { + projectId: string | null; + threadId: string | null; +} +interface BbNavigate { + toThread(threadId: string): void; + toProject(projectId: string): void; + /** + * Navigate to one of this plugin's own nav panels by its `path`. + * `subPath` targets a location inside the panel (the component's + * `subPath` prop); `replace` swaps the current history entry instead of + * pushing — use it for redirects so back does not bounce. + */ + toPluginPanel(path: string, options?: { + subPath?: string; + replace?: boolean; + }): void; + /** + * Navigate to the root compose surface (the new-thread screen). Pass + * `initialPrompt` to seed the composer draft and `focusPrompt` to focus the + * composer on arrival — the pairing behind "Create via chat" style entry + * points that drop the user into chat with a prefilled prompt. + */ + toCompose(options?: { + initialPrompt?: string; + focusPrompt?: boolean; + }): void; + /** + * Open one of this plugin's registered thread-panel actions in the current + * thread surface. Returns false when the surface has no thread side panel or + * the action is unavailable. + */ + experimental_openThreadPanel(options: { + actionId: string; + title?: string; + params?: JsonValue; + }): boolean; +} +/** + * Everything `@bb/plugin-sdk/app` resolves to at runtime. The BB app builds + * the real implementation and `satisfies` this interface; `bb plugin build` + * shims the specifier to that object on `globalThis.__bbPluginRuntime`. + */ +interface PluginSdkApp { + definePluginApp(setup: PluginAppSetup): PluginAppDefinition; + useRpc(): PluginRpcClient; + useRealtime(channel: string, handler: (payload: unknown) => void): void; + /** + * Observe the same shared connection that delivers `useRealtime` signals. + * Use a subsequent transition to `connected` to reconcile server state that + * may have changed while ephemeral signals could not be delivered. The first + * connection can transition from `connecting` and is not a reconnection. + */ + useRealtimeConnectionState(): PluginRealtimeConnectionState; + useSettings(): PluginSettingsState; + useBbContext(): BbContext; + useBbNavigate(): BbNavigate; + useComposer(): PluginComposerApi; + /** + * The host-owned chat component (see {@link ThreadChatProps}). Together + * with `Markdown`, the only components the SDK ships — everything else + * stays vendored per §5.5. + */ + experimental_ThreadChat: ComponentType; + /** + * The host-owned chat-message markdown renderer (see + * {@link MarkdownProps}). + */ + experimental_Markdown: ComponentType; + useComposerView(): ComposerView; +} + +declare const definePluginApp: (setup: PluginAppSetup) => PluginAppDefinition; +declare const experimental_ThreadChat: react.ComponentType; +declare const experimental_Markdown: react.ComponentType; +declare const useRpc: , StandardSchemaV1>>>>() => PluginRpcClient; +declare const useRealtime: (channel: string, handler: (payload: unknown) => void) => void; +declare const useRealtimeConnectionState: () => PluginRealtimeConnectionState; +declare const useSettings: () => PluginSettingsState; +declare const useBbContext: () => BbContext; +declare const useBbNavigate: () => BbNavigate; +declare const useComposer: () => PluginComposerApi; +declare const useComposerView: () => ComposerView; + +export { definePluginApp, experimental_Markdown, experimental_ThreadChat, useBbContext, useBbNavigate, useComposer, useComposerView, useRealtime, useRealtimeConnectionState, useRpc, useSettings }; +export type { BbContext, BbNavigate, ComposerCustomization, ComposerPlusMenuItem, ComposerRichTextSpec, ComposerStructuredDraft, ComposerView, JsonValue, MarkdownProps, PluginAppBuilder, PluginAppComposer, PluginAppContentScripts, PluginAppDefinition, PluginAppSetup, PluginAppSlots, PluginComposerApi, PluginComposerMention, PluginComposerScope, PluginComposerTextEffect, PluginComposerThreadRowStatus, PluginContentScriptContext, PluginContentScriptDisposer, PluginContentScriptRegistration, PluginFileOpenerProps, PluginFileOpenerRegistration, PluginFileOpenerSource, PluginHomepageSectionProps, PluginHomepageSectionRegistration, PluginMessageActionContext, PluginMessageActionRegistration, PluginMessageActionThreadPanelOptions, PluginMessageDirectiveMessage, PluginMessageDirectiveOpenWorkspaceFile, PluginMessageDirectiveProps, PluginMessageDirectiveRegistration, PluginNavPanelProps, PluginNavPanelRegistration, PluginPendingInteractionProps, PluginPendingInteractionRegistration, PluginPendingInteractionView, PluginRealtimeConnectionState, PluginRpcCallArgs, PluginRpcClient, PluginRpcContract, PluginRpcError, PluginRpcErrorCode, PluginRpcHandlers, PluginRpcIssuePathSegment, PluginRpcMethodContract, PluginRpcResult, PluginRpcValidationIssue, PluginSdkApp, PluginSettingsSectionProps, PluginSettingsSectionRegistration, PluginSettingsState, PluginSidebarFooterActionContext, PluginSidebarFooterActionProps, PluginSidebarFooterActionRegistration, PluginThreadPanelActionContext, PluginThreadPanelActionRegistration, PluginThreadPanelProps, StandardSchemaV1, StandardSchemaV1InferInput, StandardSchemaV1InferOutput, StandardSchemaV1Issue, StandardSchemaV1Result, ThreadChatMessageAction, ThreadChatMessageReference, ThreadChatProps }; diff --git a/plugins/thread-organizer/types/bb-plugin-sdk.d.ts b/plugins/thread-organizer/types/bb-plugin-sdk.d.ts new file mode 100644 index 0000000..8125dda --- /dev/null +++ b/plugins/thread-organizer/types/bb-plugin-sdk.d.ts @@ -0,0 +1,11762 @@ +// Portable type declarations for `@bb/plugin-sdk`. Unpublished BB +// workspace contracts are flattened; public subpaths may reuse the +// package root without requiring any other @bb/* package. +// +// Confused by the API, or need a symbol that isn't here? Clone the BB repo +// and read the real source: https://github.com/ymichael/bb + +import { ComponentType, ReactNode } from 'react'; +import Database from 'better-sqlite3'; +import { Context } from 'hono'; +import * as z from 'zod'; +import { z as z$1 } from 'zod'; + +/** + * A value that survives a JSON round trip without coercion or data loss. + * + * Host boundaries still validate values at runtime because TypeScript cannot + * exclude non-finite numbers and plugin bundles can bypass static types. + */ +type JsonValue$1 = string | number | boolean | null | JsonValue$1[] | { + [key: string]: JsonValue$1; +}; + +/** A JSON-safe path segment reported by a Standard Schema validation issue. */ +type PluginRpcIssuePathSegment = string | number; +/** Validator-neutral validation detail carried by an RPC error envelope. */ +interface PluginRpcValidationIssue { + message: string; + path?: PluginRpcIssuePathSegment[]; +} +/** Stable wire error categories for plugin RPC. */ +type PluginRpcErrorCode = "invalid_json" | "invalid_input" | "handler_error" | "invalid_output" | "non_json_result" | "unknown_method"; +/** Structured RPC failure returned as `{ ok: false, error }`. */ +interface PluginRpcError { + code: PluginRpcErrorCode; + message: string; + issues?: PluginRpcValidationIssue[]; +} +/** + * The validator-neutral subset of Standard Schema v1 used by plugin RPC. + * Zod 4 schemas implement this interface directly; other validators can do + * the same without becoming part of BB's public protocol. + */ +interface StandardSchemaV1 { + readonly "~standard": { + readonly version: 1; + readonly vendor: string; + readonly validate: (value: unknown) => StandardSchemaV1Result | Promise>; + readonly types?: { + readonly input: Input; + readonly output: Output; + }; + }; +} +type StandardSchemaV1Result = { + readonly value: Output; + readonly issues?: undefined; +} | { + readonly issues: readonly StandardSchemaV1Issue[]; +}; +interface StandardSchemaV1Issue { + readonly message: string; + readonly path?: PropertyKey | readonly (PropertyKey | { + readonly key: PropertyKey; + })[]; +} +type StandardSchemaV1InferInput = NonNullable["input"]; +type StandardSchemaV1InferOutput = NonNullable["output"]; +interface PluginRpcMethodContract { + readonly input: InputSchema; + readonly output: OutputSchema; +} +type PluginRpcContract = Readonly>; +/** Define a shared RPC contract while preserving exact method/schema types. */ +declare function defineRpcContract(contract: Contract): Contract; +type PluginRpcHandlers = { + [Method in keyof Contract]: (input: StandardSchemaV1InferOutput) => StandardSchemaV1InferInput | Promise>; +}; +type PluginRpcCallInput = StandardSchemaV1InferInput; +type PluginRpcCallArgs = null extends PluginRpcCallInput ? [input?: PluginRpcCallInput] : [input: PluginRpcCallInput]; +type PluginRpcResult = StandardSchemaV1InferOutput; + +/** + * The `@bb/plugin-sdk/app` contract (plugin design §5.2) — pure types with no + * side effects. The BB app imports these to keep its real implementation in + * sync (`satisfies PluginSdkApp`). Plugin authors import the same shapes through + * `@bb/plugin-sdk/app`. + * + * Per-slot props are versioned contracts: additive-only within an SDK major. + */ +/** Props passed to a `homepageSection` component. */ +interface PluginHomepageSectionProps { + /** Project in view on the compose surface; null when none is selected. */ + projectId: string | null; +} +/** + * Props passed to a `settingsSection` component. + * + * Deliberately empty in V1; versioned additive like the other slot props. + */ +interface PluginSettingsSectionProps { +} +/** Props passed to a `navPanel` component (it owns its whole route). */ +interface PluginNavPanelProps { + /** + * The route remainder after the panel root, "" at the root. The panel's + * route is `/plugins///*`, so a deep link like + * `/plugins/notes/notes/work/ideas.md` renders the panel with + * `subPath: "work/ideas.md"`. Navigate within the panel via + * `useBbNavigate().toPluginPanel(path, { subPath })` — browser + * back/forward then walks panel-internal history. + */ + subPath: string; +} +/** Props passed to a panel tab opened by a `threadPanelAction`. */ +interface PluginThreadPanelProps { + threadId: string; + /** + * The JSON value the action's `openPanel` call passed (round-tripped + * through persistence, so the tab restores across reloads); null when the + * action opened the panel without params. + */ + params: JsonValue$1 | null; +} +interface PluginPendingInteractionView { + id: string; + threadId: string; + title: string; + payload: JsonValue$1; + createdAt: number; + expiresAt: number | null; +} +interface PluginPendingInteractionProps { + interaction: PluginPendingInteractionView; + submit(value: JsonValue$1): Promise; + cancel(): Promise; +} +/** + * Props for a `sidebarFooterAction` — host-rendered (no plugin component). + * Deliberately empty; the registration's `run` carries the behavior. + */ +interface PluginSidebarFooterActionProps { +} +/** + * Where a file being opened by a `fileOpener` lives. `path` semantics follow + * the source: workspace paths are relative to the environment's worktree, + * thread-storage paths are relative to the thread's storage root, host paths + * are absolute on the thread's host. + */ +interface PluginFileOpenerSource { + kind: "workspace" | "host" | "thread-storage"; + threadId: string | null; + environmentId: string | null; + projectId: string | null; +} +/** Props passed to a `fileOpener` component (rendered as a panel file tab). */ +interface PluginFileOpenerProps { + path: string; + source: PluginFileOpenerSource; +} +/** + * Message context passed to a `messageDirective` component — the assistant + * (or nested agent) message that contained the directive. + */ +interface PluginMessageDirectiveMessage { + id: string; + threadId: string; + turnId: string | null; + projectId: string | null; +} +/** + * Open a worktree-relative file in the host's workspace file viewer. Returns + * true when the host accepted the path; false when the path is invalid or the + * viewer declined it. + */ +type PluginMessageDirectiveOpenWorkspaceFile = (path: string) => boolean; +/** + * Props passed to a `messageDirective` component. Attributes are untrusted + * strings parsed from the directive; the plugin validates its own fields. + */ +interface PluginMessageDirectiveProps { + /** Parsed, untrusted directive attributes (e.g. `{ file: "demo.html" }`). */ + attributes: Readonly>; + /** Original directive source text (useful for diagnostics / crash fallback). */ + source: string; + message: PluginMessageDirectiveMessage; + /** + * Opens a worktree-relative file in the host's workspace file viewer. Null + * when the message surface has no workspace viewer available. + */ + openWorkspaceFile: PluginMessageDirectiveOpenWorkspaceFile | null; +} +interface PluginHomepageSectionRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + title: string; + component: ComponentType; +} +interface PluginSettingsSectionRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Optional host-rendered section heading. */ + title?: string; + /** + * Optional one-line host-rendered subheading under `title`, in the built-in + * SettingsSection idiom (ignored when `title` is absent). + */ + description?: string; + component: ComponentType; +} +interface PluginNavPanelRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + title: string; + /** Icon hint (BB icon name); unknown names fall back to a generic icon. */ + icon: string; + /** URL segment under `/plugins//`; letters, digits, `-`, `_`. */ + path: string; + component: ComponentType; + /** + * Optional component rendered on the right side of the shared title bar + * (e.g. a sync button or a count). Contained separately from the body: a + * throwing headerContent is hidden without breaking the title bar. + */ + headerContent?: ComponentType; +} +/** Context handed to a `threadPanelAction`'s `run`. */ +interface PluginThreadPanelActionContext { + /** The thread whose panel launcher invoked the action. */ + threadId: string; + /** + * Open a tab in the thread's side panel rendering this action's + * `component`. `title` labels the tab (default: the action's `title`); + * `params` must be JSON-serializable — it is persisted with the tab and + * reaches the component as its `params` prop. Opening with params + * identical to an already-open tab of this action focuses that tab + * (updating its title) instead of duplicating it. May be called more than + * once (different params ⇒ multiple tabs) or not at all. + */ + openPanel(options?: { + title?: string; + params?: JsonValue$1; + }): void; +} +interface PluginThreadPanelActionRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Label of the action row in the panel's new-tab launcher. */ + title: string; + /** + * Icon hint (BB icon name) used when the plugin ships no logo; the + * launcher row and opened tabs prefer the plugin's logo. + */ + icon?: string; + /** Rendered inside every panel tab this action opens. */ + component: ComponentType; + /** + * How the host frames the tab content. "padded" (default) wraps the + * component in the panel's scroll container with standard padding — + * right for document-like content. "flush" gives the component the full + * tab area (no padding, definite height, no host scrolling) — right for + * app-like content that manages its own layout, such as + * `experimental_ThreadChat`. + */ + layout?: "padded" | "flush"; + /** + * Runs when the user activates the action: call your RPC methods, show a + * toast, and/or open panel tabs via `context.openPanel`. Omitted = + * immediately open a panel tab with defaults. Errors (sync or async) are + * contained and logged; they never break the launcher. + */ + run?(context: PluginThreadPanelActionContext): void | Promise; +} +interface PluginPendingInteractionRegistration { + /** Matches `rendererId` passed to `bb.ui.requestInput`. */ + id: string; + component: ComponentType; +} +/** Context handed to a `sidebarFooterAction`'s `run`. */ +interface PluginSidebarFooterActionContext { + /** + * Navigate to this plugin's Settings detail page + * (`/settings/plugins/`), where declarative settings and + * `settingsSection` slots render. + */ + openSettings(): void; +} +/** + * An icon button in the app sidebar footer (next to Settings / bug report). + * Host-rendered for consistent chrome — plugins supply icon, label, and + * `run` behavior only. + */ +interface PluginSidebarFooterActionRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Tooltip and accessible label for the icon button. */ + title: string; + /** Icon hint (BB icon name); unknown names fall back to a generic icon. */ + icon: string; + /** + * Runs when the user activates the action (e.g. call `openSettings()`, + * open a panel via other surfaces, toast). Errors (sync or async) are + * contained and logged; they never break the sidebar. + */ + run(context: PluginSidebarFooterActionContext): void | Promise; +} +/** + * Register this plugin as a viewer/editor for file extensions. The user + * picks (and can set as default) an opener per extension via the file tab's + * "Open with" menu; matching files opened in the panel then render + * `component` in a plugin tab instead of the built-in preview. Applies to + * working-tree, host, and thread-storage files — never to git-ref snapshots + * (diff views always use the built-in preview). The built-in preview stays + * one menu click away, and a missing/disabled opener falls back to it. + */ +interface PluginFileOpenerRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Label in the "Open with" menu (e.g. "Notes editor"). */ + title: string; + /** Lowercase extensions without the dot (e.g. ["md", "mdx"]). */ + extensions: readonly string[]; + component: ComponentType; +} +/** + * Register a leaf message directive rendered inside assistant (and nested + * agent) message Markdown. `id` is the directive name: `inline-vis` matches + * `::inline-vis{file="demo.html"}`. + */ +interface PluginMessageDirectiveRegistration { + /** + * The directive name. Lowercase kebab-case beginning with a letter. + */ + id: string; + component: ComponentType; +} +/** + * A narrow, stable reference to one rendered chat message — NOT an internal + * timeline row. `sourceSeqEnd` is the last source event sequence the message + * covers, the anchor the server accepts for provider-history forks. + */ +interface ThreadChatMessageReference { + id: string; + threadId: string; + role: "user" | "assistant"; + /** Visible text of the message. */ + text: string; + sourceSeqEnd: number; +} +interface PluginMessageActionThreadPanelOptions { + /** A `threadPanelAction` id registered by this same plugin. */ + actionId: string; + title?: string; + params?: JsonValue$1; +} +/** Context handed to a `messageAction`'s `run`. */ +interface PluginMessageActionContext { + /** The thread whose timeline surfaced the action. */ + threadId: string; + message: ThreadChatMessageReference; + /** + * Present only when the action was invoked from the text-selection menu; + * the exact text the user highlighted inside `message`. + */ + selectedText?: string; + /** + * Open one of this plugin's `threadPanelAction` components in the current + * thread's side panel — the registration-callback equivalent of + * `useBbNavigate().experimental_openThreadPanel`. Returns true when the host + * accepted (the action id exists and the surface has a panel); false + * otherwise. + */ + openPanel(options: PluginMessageActionThreadPanelOptions): boolean; +} +/** + * An action on chat messages: an icon button in the per-message action bar + * (user and assistant messages) and an entry in the assistant-message + * text-selection menu. Host-rendered chrome — the plugin supplies title, + * icon hint, and `run` behavior only. + */ +interface PluginMessageActionRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Tooltip / menu label for the action. */ + title: string; + /** Icon hint (BB icon name); unknown names fall back to a generic icon. */ + icon?: string; + /** + * Runs when the user activates the action. Errors (sync or async) are + * contained and logged; they never break the timeline. + */ + run(context: PluginMessageActionContext): void | Promise; +} +interface PluginAppSlots { + homepageSection(registration: PluginHomepageSectionRegistration): void; + settingsSection(registration: PluginSettingsSectionRegistration): void; + navPanel(registration: PluginNavPanelRegistration): void; + threadPanelAction(registration: PluginThreadPanelActionRegistration): void; + pendingInteraction(registration: PluginPendingInteractionRegistration): void; + sidebarFooterAction(registration: PluginSidebarFooterActionRegistration): void; + fileOpener(registration: PluginFileOpenerRegistration): void; + messageDirective(registration: PluginMessageDirectiveRegistration): void; + experimental_messageAction(registration: PluginMessageActionRegistration): void; +} +interface PluginAppComposer { + customize(registration: ComposerCustomization): void; +} +/** Stable lifecycle values for one content-script instance in one bb client. */ +interface PluginContentScriptContext { + /** The id of the plugin that owns this script. */ + readonly pluginId: string; + /** Monotonic per-client generation, starting at 1. */ + readonly generation: number; + /** Aborted before cleanup begins on replacement, deactivation, or teardown. */ + readonly signal: AbortSignal; +} +/** Cleanup returned by a frontend content script. */ +type PluginContentScriptDisposer = () => void | Promise; +/** + * Trusted same-origin JavaScript/TypeScript mounted once per active frontend + * generation in each bb app window or browser tab. + */ +interface PluginContentScriptRegistration { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** + * Install behavior into the bb app shell. The host awaits a returned + * promise, contains failures, and calls the returned disposer exactly once. + */ + mount(context: PluginContentScriptContext): void | PluginContentScriptDisposer | Promise; +} +/** Experimental lifecycle surface for trusted frontend content scripts. */ +interface PluginAppContentScripts { + register(registration: PluginContentScriptRegistration): void; +} +interface PluginAppBuilder { + slots: PluginAppSlots; + composer: PluginAppComposer; + experimental_contentScripts: PluginAppContentScripts; +} +type PluginAppSetup = (app: PluginAppBuilder) => void; +/** + * The opaque product of `definePluginApp` — a plugin's `app.tsx` default + * export. The host re-runs `setup` against a fresh collector on every + * (re)interpretation, replacing that plugin's registrations wholesale. + */ +interface PluginAppDefinition { + /** Brand the host checks before interpreting a bundle's default export. */ + readonly __bbPluginApp: true; + readonly setup: PluginAppSetup; +} +interface PluginRpcClient { + /** + * Invoke one of the plugin's `bb.rpc` methods (POST + * /api/v1/plugins/<id>/rpc/<method>). Resolves with the method's + * inferred output; rejects with an `Error` carrying the server's message, + * stable `code`, and validation `issues` when present. + */ + call>(method: Method, ...args: PluginRpcCallArgs): Promise>; +} +interface PluginSettingsState { + /** + * Effective non-secret setting values (secret settings are excluded — + * read them server-side). Undefined while loading or unavailable. + */ + values: Record | undefined; + isLoading: boolean; +} +/** State of the app's shared realtime connection to the bb server. */ +type PluginRealtimeConnectionState = "connecting" | "connected" | "reconnecting"; +/** Where `useComposer()` writes. */ +type PluginComposerScope = { + kind: "thread"; + threadId: string; +} | { + kind: "queued-message"; + threadId: string; + queuedMessageId: string; +} | { + kind: "side-chat"; + projectId: string; + parentThreadId: string; + tabId: string; + childThreadId: string | null; +} | { + kind: "new-thread"; + /** Root compose's effective selected project; null only while unresolved. */ + projectId: string | null; +}; +/** One plugin-owned composer customization registration. */ +interface ComposerCustomization { + /** Unique within the plugin; letters, digits, `-`, `_`. */ + id: string; + /** Composer kinds where this customization is active; omit for all kinds. */ + scopes?: readonly PluginComposerScope["kind"][]; + actions?: readonly { + id: string; + component: ComponentType; + }[]; + banners?: readonly { + id: string; + /** Host chrome around the banner. Defaults to `"card"`. */ + chrome?: "card" | "bare"; + component: ComponentType; + }[]; + plusMenu?: readonly ComposerPlusMenuItem[]; + richText?: ComposerRichTextSpec; +} +/** Host-rendered menu row in the composer's `+` menu. */ +interface ComposerPlusMenuItem { + id: string; + label: string; + /** BB icon name; unknown names fall back to the generic plugin icon. */ + icon?: string; + /** Accessible description for the host-rendered row. */ + description?: string; + disabled?: boolean | ((view: ComposerView) => boolean); + run(context: { + composer: PluginComposerApi; + view: ComposerView; + }): void | Promise; +} +/** Reactive read-side of the composer a plugin surface is mounted in. */ +interface ComposerView { + scope: PluginComposerScope; + layout: "expanded" | "compact" | "zen"; + draft: { + text: string; + isEmpty: boolean; + attachmentCount: number; + }; + run: { + isRunning: boolean; + isSubmitting: boolean; + }; +} +interface ComposerRichTextSpec { + /** Content-derived paint: match ranges receive `className`; text is never mutated. */ + effects?: readonly { + id: string; + /** Plain-text offsets into the current structured draft. */ + match(text: string): readonly { + from: number; + to: number; + }[]; + className: string; + }[]; + /** Debounced, read-only observation of the structured draft. */ + onDraftChange?(draft: ComposerStructuredDraft, view: ComposerView): void; +} +interface ComposerStructuredDraft { + text: string; + mentions: readonly { + from: number; + to: number; + provider: string; + id: string; + label: string; + }[]; +} +/** Host-rendered paint applied to the editable composer text. */ +interface PluginComposerTextEffect { + className: string; +} +/** Host-rendered status that temporarily replaces a thread's draft glyph. */ +interface PluginComposerThreadRowStatus { + /** BB icon-name hint; unknown names fall back to the generic plugin icon. */ + icon: string; + /** Accessible label for the status glyph. */ + label: string; + /** Semantic host color for the status glyph. Defaults to the neutral tone. */ + tone?: "default" | "success"; +} +/** An @-mention pill bound to one of the calling plugin's mention providers. */ +interface PluginComposerMention { + /** Mention provider id registered by THIS plugin via `bb.ui.registerMentionProvider`. */ + provider: string; + /** Item id your provider's `resolve` will receive at send time. */ + id: string; + /** Pill text shown in the composer. */ + label: string; +} +/** + * Programmatic access to the chat composer draft — the same shared draft the + * built-in "Add to chat" affordances (file preview, diff, terminal selections) + * write to. While a queued message is being edited, writes land in that + * message's inline editor. In a side chat, writes land in the visible side-chat + * draft. Otherwise, inside a thread context writes land in that thread's draft; + * anywhere else (nav panel, homepage section) they seed the new-thread composer + * draft, which persists until the user sends or clears it. + */ +interface PluginComposerApi { + scope: PluginComposerScope; + /** Current plain text for this composer scope. */ + readonly text: string; + /** + * Replace the draft's plain text. Attachments are preserved. Inline mentions + * outside the changed range are preserved and rebased; mentions overlapped + * by the replacement are removed because their text representation changed. + */ + setText(next: string): void; + /** + * Replace the draft's plain text from the latest committed value. Uses the + * same structured-state reconciliation as `setText`. + */ + updateText(updater: (current: string) => string): void; + /** Clear plain text without clearing independently attached files. */ + clear(): void; + /** + * Apply a host-rendered effect to this composer's editable text, or clear it. + * Effects are scoped to the calling plugin and automatically clear when the + * slot unmounts or its composer scope changes. + */ + setTextEffect(effect: PluginComposerTextEffect | null): void; + /** + * Lock or unlock editing for this composer. Locks are scoped to the calling + * plugin and automatically release when the slot unmounts or its composer + * scope changes. + */ + setInputLock(locked: boolean): void; + /** + * Replace this composer's thread-row draft glyph with a host-rendered status, + * or clear it. New-thread composers have no row, so calls are a no-op. + * Side-chat and queued side-chat scopes decorate the visible parent-thread + * row. Status is scoped to the calling plugin and automatically clears when + * the slot unmounts or its composer scope changes. + */ + setThreadRowStatus(status: PluginComposerThreadRowStatus | null): void; + /** + * Append text to the draft as a `> ` blockquote block and focus the + * composer. Blank text is a no-op. This is the "reference this selection + * in chat" primitive. + */ + addQuote(text: string): void; + /** + * Insert an @-mention pill that resolves through this plugin's mention + * provider at send time — the durable way to reference an entity whose + * content should be fetched fresh when the message is sent. + */ + insertMention(mention: PluginComposerMention): void; + /** Focus the composer caret at the end of the draft. */ + focus(): void; +} +/** + * A consumer-supplied action on the messages of one `ThreadChat` instance, + * rendered in the embedded timeline's per-message action bar alongside the + * native and slot-registered actions. Unlike the `messageAction` slot this is + * scoped to the rendering component, not registered globally. + */ +interface ThreadChatMessageAction { + /** Unique within this ThreadChat instance; letters, digits, `-`, `_`. */ + id: string; + /** Tooltip / menu label for the action. */ + title: string; + /** Icon hint (BB icon name); unknown names fall back to a generic icon. */ + icon?: string; + /** + * Message roles the action applies to. Omitted = both user and assistant + * messages. + */ + roles?: readonly ("user" | "assistant")[]; + /** + * Runs when the user activates the action. Errors (sync or async) are + * contained and logged; they never break the timeline. + */ + run(message: ThreadChatMessageReference): void | Promise; +} +/** + * Props of the host-owned `ThreadChat` component — one thread's chat + * (timeline, and for the composer variants the full send/queue/draft + * engine), rendered by the BB app inside a plugin slot. This is the + * deliberate exception to the no-host-components rule (§5.5): a stable + * product capability, not a UI kit. Versioned additive like slot props; + * internal timeline rows, query hooks, and prompt-box configuration are + * deliberately not exposed. + */ +interface ThreadChatProps { + threadId: string; + /** + * "full" (default) is the page presentation (centered reading width); + * "compact" is the side-panel presentation; "timeline" renders the + * transcript without a composer. + */ + variant?: "full" | "compact" | "timeline"; + /** + * "contained" (default) fills and scrolls inside a bounded parent; + * "document" grows with its content and defers scrolling to the page. + */ + layout?: "contained" | "document"; + /** Bump to focus the composer (ignored by `variant: "timeline"`). */ + focusRequest?: number; + className?: string; + /** Rendered above the conversation, scrolling with it. */ + leadingContent?: ReactNode; + /** + * Actions rendered in this instance's per-message action bar (see + * {@link ThreadChatMessageAction}). + */ + messageActions?: readonly ThreadChatMessageAction[]; +} +/** + * Props of the host-owned `Markdown` component — bb's chat message renderer + * (the same typography, spacing, and code styling as timeline messages). + * Use it wherever plugin UI quotes or previews message content so it reads + * like the rest of the chat. Like `ThreadChat`, this is a stable product + * capability, not a UI kit; renderer internals stay private. + */ +interface MarkdownProps { + /** Markdown source, rendered exactly like a chat message body. */ + content: string; + className?: string; +} +/** Current app selection, derived from the route. */ +interface BbContext { + projectId: string | null; + threadId: string | null; +} +interface BbNavigate { + toThread(threadId: string): void; + toProject(projectId: string): void; + /** + * Navigate to one of this plugin's own nav panels by its `path`. + * `subPath` targets a location inside the panel (the component's + * `subPath` prop); `replace` swaps the current history entry instead of + * pushing — use it for redirects so back does not bounce. + */ + toPluginPanel(path: string, options?: { + subPath?: string; + replace?: boolean; + }): void; + /** + * Navigate to the root compose surface (the new-thread screen). Pass + * `initialPrompt` to seed the composer draft and `focusPrompt` to focus the + * composer on arrival — the pairing behind "Create via chat" style entry + * points that drop the user into chat with a prefilled prompt. + */ + toCompose(options?: { + initialPrompt?: string; + focusPrompt?: boolean; + }): void; + /** + * Open one of this plugin's registered thread-panel actions in the current + * thread surface. Returns false when the surface has no thread side panel or + * the action is unavailable. + */ + experimental_openThreadPanel(options: { + actionId: string; + title?: string; + params?: JsonValue$1; + }): boolean; +} +/** + * Everything `@bb/plugin-sdk/app` resolves to at runtime. The BB app builds + * the real implementation and `satisfies` this interface; `bb plugin build` + * shims the specifier to that object on `globalThis.__bbPluginRuntime`. + */ +interface PluginSdkApp { + definePluginApp(setup: PluginAppSetup): PluginAppDefinition; + useRpc(): PluginRpcClient; + useRealtime(channel: string, handler: (payload: unknown) => void): void; + /** + * Observe the same shared connection that delivers `useRealtime` signals. + * Use a subsequent transition to `connected` to reconcile server state that + * may have changed while ephemeral signals could not be delivered. The first + * connection can transition from `connecting` and is not a reconnection. + */ + useRealtimeConnectionState(): PluginRealtimeConnectionState; + useSettings(): PluginSettingsState; + useBbContext(): BbContext; + useBbNavigate(): BbNavigate; + useComposer(): PluginComposerApi; + /** + * The host-owned chat component (see {@link ThreadChatProps}). Together + * with `Markdown`, the only components the SDK ships — everything else + * stays vendored per §5.5. + */ + experimental_ThreadChat: ComponentType; + /** + * The host-owned chat-message markdown renderer (see + * {@link MarkdownProps}). + */ + experimental_Markdown: ComponentType; + useComposerView(): ComposerView; +} + +/** + * App-wide server-backed preferences. + * Client-local settings stay in the frontend localStorage helpers instead. + */ +declare const appSettingsSchema: z$1.ZodObject<{ + caffeinate: z$1.ZodBoolean; + showKeyboardHints: z$1.ZodBoolean; + showUnhandledProviderEvents: z$1.ZodBoolean; + codexMemoryEnabled: z$1.ZodBoolean; + claudeCodeMemoryEnabled: z$1.ZodBoolean; + codexSubagentsDisabled: z$1.ZodBoolean; + claudeCodeSubagentsDisabled: z$1.ZodBoolean; + claudeCodeWorkflowsDisabled: z$1.ZodBoolean; +}, z$1.core.$strict>; +type AppSettings = z$1.infer; + +declare const appKeybindingOverridesSchema: z$1.ZodArray; + shortcut: z$1.ZodNullable>; +}, z$1.core.$strict>>; +type AppKeybindingOverrides = z$1.infer; + +declare const appThemeSchema: z$1.ZodObject<{ + themeId: z$1.ZodString; + customCss: z$1.ZodNullable; + faviconColor: z$1.ZodEnum<{ + default: "default"; + red: "red"; + orange: "orange"; + yellow: "yellow"; + green: "green"; + teal: "teal"; + blue: "blue"; + purple: "purple"; + pink: "pink"; + }>; +}, z$1.core.$strip>; +type AppTheme = z$1.infer; +/** + * The complete appearance selection a client sends when changing the palette + * and/or favicon tint. The server validates `themeId` (built-in id or an + * existing custom theme) and resolves the CSS from disk for custom themes. + * Callers changing only one facet must carry the other facet forward explicitly. + */ +declare const appThemeSelectionSchema: z$1.ZodObject<{ + themeId: z$1.ZodString; + faviconColor: z$1.ZodEnum<{ + default: "default"; + red: "red"; + orange: "orange"; + yellow: "yellow"; + green: "green"; + teal: "teal"; + blue: "blue"; + purple: "purple"; + pink: "pink"; + }>; +}, z$1.core.$strip>; +type AppThemeSelection = z$1.infer; + +declare const changedMessageSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + type: z$1.ZodLiteral<"changed">; + entity: z$1.ZodLiteral<"thread">; + id: z$1.ZodOptional; + metadata: z$1.ZodOptional; + eventTypes: z$1.ZodOptional>>>>; + hasPendingInteraction: z$1.ZodOptional; + projectId: z$1.ZodOptional; + }, z$1.core.$strict>>; + changes: z$1.ZodReadonly>>; +}, z$1.core.$strict>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"changed">; + entity: z$1.ZodLiteral<"project">; + id: z$1.ZodOptional; + changes: z$1.ZodReadonly>>; +}, z$1.core.$strict>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"changed">; + entity: z$1.ZodLiteral<"environment">; + id: z$1.ZodOptional; + changes: z$1.ZodReadonly>>; +}, z$1.core.$strict>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"changed">; + entity: z$1.ZodLiteral<"host">; + id: z$1.ZodOptional; + changes: z$1.ZodReadonly>>; +}, z$1.core.$strict>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"changed">; + entity: z$1.ZodLiteral<"system">; + changes: z$1.ZodReadonly>>; +}, z$1.core.$strict>], "entity">; +type ChangedMessage = z$1.infer; + +declare const environmentSchema: z$1.ZodObject<{ + id: z$1.ZodString; + name: z$1.ZodNullable; + projectId: z$1.ZodString; + hostId: z$1.ZodString; + path: z$1.ZodNullable; + managed: z$1.ZodBoolean; + isGitRepo: z$1.ZodBoolean; + isWorktree: z$1.ZodBoolean; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + branchName: z$1.ZodNullable; + baseBranch: z$1.ZodNullable; + defaultBranch: z$1.ZodNullable; + mergeBaseBranch: z$1.ZodNullable; + status: z$1.ZodEnum<{ + error: "error"; + provisioning: "provisioning"; + ready: "ready"; + retiring: "retiring"; + destroying: "destroying"; + destroyed: "destroyed"; + }>; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; +}, z$1.core.$strip>; +type Environment = z$1.infer; + +/** + * User-opt-in experiments (the Settings → Experiments toggles). Distinct from + * `FeatureFlags`: flags are operator-set via env at server start, experiments + * are user-toggled at runtime and persisted server-side so server-owned + * policy (e.g. skill injection) can honor them. + * + * Every experiment defaults to off — opting in is the point. + */ +declare const experimentsSchema: z$1.ZodObject<{ + claudeCodeMockCliTraffic: z$1.ZodBoolean; + plugins: z$1.ZodBoolean; + sideChatPlugin: z$1.ZodBoolean; +}, z$1.core.$strip>; +type Experiments = z$1.infer; + +declare const hostSchema: z$1.ZodObject<{ + id: z$1.ZodString; + name: z$1.ZodString; + type: z$1.ZodEnum<{ + persistent: "persistent"; + }>; + status: z$1.ZodEnum<{ + connected: "connected"; + disconnected: "disconnected"; + }>; + lastSeenAt: z$1.ZodNullable; + lastRejectedProtocolVersion: z$1.ZodNullable; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; +}, z$1.core.$strip>; +type Host = z$1.infer; + +interface JsonObject { + [key: string]: JsonValue; +} +type JsonValue = string | number | boolean | null | JsonValue[] | JsonObject; + +declare const pendingInteractionResolutionSchema: z$1.ZodUnion; + grantedPermissions: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; +}, z$1.core.$strip>, z$1.ZodObject<{ + decision: z$1.ZodLiteral<"allow_for_session">; + grantedPermissions: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; +}, z$1.core.$strip>, z$1.ZodObject<{ + decision: z$1.ZodLiteral<"deny">; +}, z$1.core.$strip>], "decision">, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"user_answer">; + answers: z$1.ZodRecord; + freeText: z$1.ZodOptional; + }, z$1.core.$strip>>; +}, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin_submitted">; +}, z$1.core.$strip>]>; +type PendingInteractionResolution = z$1.infer; +declare const providerPendingInteractionSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + status: z$1.ZodEnum<{ + pending: "pending"; + interrupted: "interrupted"; + resolving: "resolving"; + resolved: "resolved"; + }>; + statusReason: z$1.ZodNullable; + createdAt: z$1.ZodNumber; + expiresAt: z$1.ZodOptional>; + resolvedAt: z$1.ZodNullable; + turnId: z$1.ZodString; + providerId: z$1.ZodString; + providerThreadId: z$1.ZodString; + providerRequestId: z$1.ZodString; + origin: z$1.ZodOptional; + providerId: z$1.ZodString; + providerThreadId: z$1.ZodString; + providerRequestId: z$1.ZodString; + }, z$1.core.$strip>>; + payload: z$1.ZodUnion; + subject: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + itemId: z$1.ZodString; + command: z$1.ZodString; + cwd: z$1.ZodNullable; + actions: z$1.ZodArray; + command: z$1.ZodString; + name: z$1.ZodString; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"listFiles">; + command: z$1.ZodString; + path: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"search">; + command: z$1.ZodString; + query: z$1.ZodNullable; + path: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"unknown">; + command: z$1.ZodString; + }, z$1.core.$strip>], "type">>; + sessionGrant: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"file_change">; + itemId: z$1.ZodString; + writeScope: z$1.ZodNullable; + sessionGrant: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"permission_grant">; + itemId: z$1.ZodString; + toolName: z$1.ZodNullable; + permissions: z$1.ZodObject<{ + network: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>; + }, z$1.core.$strip>], "kind">; + reason: z$1.ZodNullable; + availableDecisions: z$1.ZodArray>; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"user_question">; + questions: z$1.ZodArray; + multiSelect: z$1.ZodBoolean; + options: z$1.ZodOptional; + }, z$1.core.$strip>>>; + allowFreeText: z$1.ZodBoolean; + }, z$1.core.$strip>>; + }, z$1.core.$strip>]>; + resolution: z$1.ZodNullable; + grantedPermissions: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + decision: z$1.ZodLiteral<"allow_for_session">; + grantedPermissions: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + decision: z$1.ZodLiteral<"deny">; + }, z$1.core.$strip>], "decision">, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"user_answer">; + answers: z$1.ZodRecord; + freeText: z$1.ZodOptional; + }, z$1.core.$strip>>; + }, z$1.core.$strip>]>>; +}, z$1.core.$strip>; +type ProviderPendingInteraction = z$1.infer; +declare const pluginPendingInteractionSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + status: z$1.ZodEnum<{ + pending: "pending"; + interrupted: "interrupted"; + resolving: "resolving"; + resolved: "resolved"; + }>; + statusReason: z$1.ZodNullable; + createdAt: z$1.ZodNumber; + expiresAt: z$1.ZodOptional>; + resolvedAt: z$1.ZodNullable; + turnId: z$1.ZodNullable; + origin: z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + rendererId: z$1.ZodString; + }, z$1.core.$strip>; + payload: z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + title: z$1.ZodString; + data: z$1.ZodType>; + }, z$1.core.$strip>; + resolution: z$1.ZodNullable; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type PluginPendingInteraction = z$1.infer; +type PendingInteraction = ProviderPendingInteraction | PluginPendingInteraction; + +declare const projectSourceSchema: z$1.ZodObject<{ + id: z$1.ZodString; + projectId: z$1.ZodString; + isDefault: z$1.ZodBoolean; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + type: z$1.ZodLiteral<"local_path">; + hostId: z$1.ZodString; + path: z$1.ZodString; +}, z$1.core.$strip>; +type ProjectSource = z$1.infer; + +declare const resolvedThreadExecutionOptionsSchema: z$1.ZodObject<{ + seq: z$1.ZodOptional; + model: z$1.ZodString; + serviceTier: z$1.ZodEnum<{ + default: "default"; + fast: "fast"; + }>; + reasoningLevel: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + permissionMode: z$1.ZodEnum<{ + full: "full"; + auto: "auto"; + "accept-edits": "accept-edits"; + }>; + source: z$1.ZodEnum<{ + "client/thread/start": "client/thread/start"; + "client/turn/requested": "client/turn/requested"; + "client/turn/start": "client/turn/start"; + }>; +}, z$1.core.$strip>; +type ResolvedThreadExecutionOptions = z$1.infer; +declare const projectExecutionDefaultsSchema: z$1.ZodObject<{ + providerId: z$1.ZodString; + model: z$1.ZodString; + serviceTier: z$1.ZodEnum<{ + default: "default"; + fast: "fast"; + }>; + reasoningLevel: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + permissionMode: z$1.ZodEnum<{ + full: "full"; + auto: "auto"; + "accept-edits": "accept-edits"; + }>; +}, z$1.core.$strip>; +type ProjectExecutionDefaults = z$1.infer; + +/** All thread events — provider-originated or system-originated. */ +declare const threadEventSchema: z$1.ZodPipe; + threadId: z$1.ZodString; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"thread/identity">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"turn/started">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"turn/completed">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodNullable; + status: z$1.ZodEnum<{ + completed: "completed"; + failed: "failed"; + interrupted: "interrupted"; + }>; + error: z$1.ZodOptional>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"turn/input/accepted">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + clientRequestId: z$1.ZodString; + scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"turn">; + turnId: z$1.ZodString; + }, z$1.core.$strip>], "kind">; +}, z$1.core.$strict>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"thread/name/updated">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + threadName: z$1.ZodString; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"thread/compacted">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"thread/goal/updated">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + objective: z$1.ZodString; + status: z$1.ZodEnum<{ + paused: "paused"; + active: "active"; + budgetLimited: "budgetLimited"; + complete: "complete"; + }>; + tokenBudget: z$1.ZodNullable; + tokensUsed: z$1.ZodNumber; + timeUsedSeconds: z$1.ZodNumber; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"thread/goal/cleared">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/started">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + item: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + type: z$1.ZodLiteral<"userMessage">; + id: z$1.ZodString; + content: z$1.ZodArray; + text: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + }, z$1.core.$strip>], "type">>; + clientRequestId: z$1.ZodOptional; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strict>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"agentMessage">; + id: z$1.ZodString; + text: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"commandExecution">; + id: z$1.ZodString; + command: z$1.ZodString; + cwd: z$1.ZodString; + status: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + failed: "failed"; + interrupted: "interrupted"; + }>; + approvalStatus: z$1.ZodNullable>; + aggregatedOutput: z$1.ZodOptional; + exitCode: z$1.ZodOptional; + durationMs: z$1.ZodOptional; + truncation: z$1.ZodOptional>; + result: z$1.ZodOptional>; + resultText: z$1.ZodOptional>; + }, z$1.core.$strip>>; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"fileChange">; + id: z$1.ZodString; + changes: z$1.ZodArray; + movePath: z$1.ZodOptional; + diff: z$1.ZodOptional; + }, z$1.core.$strip>>; + status: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + failed: "failed"; + interrupted: "interrupted"; + }>; + approvalStatus: z$1.ZodNullable>; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"webSearch">; + id: z$1.ZodString; + queries: z$1.ZodArray; + resultText: z$1.ZodNullable; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"webFetch">; + id: z$1.ZodString; + url: z$1.ZodString; + prompt: z$1.ZodNullable; + pattern: z$1.ZodNullable; + resultText: z$1.ZodNullable; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"imageView">; + id: z$1.ZodString; + path: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"toolCall">; + id: z$1.ZodString; + server: z$1.ZodOptional; + tool: z$1.ZodString; + arguments: z$1.ZodOptional>; + status: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + failed: "failed"; + interrupted: "interrupted"; + }>; + result: z$1.ZodOptional; + error: z$1.ZodOptional; + durationMs: z$1.ZodOptional; + truncation: z$1.ZodOptional>; + result: z$1.ZodOptional>; + resultText: z$1.ZodOptional>; + }, z$1.core.$strip>>; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"reasoning">; + id: z$1.ZodString; + summary: z$1.ZodArray; + content: z$1.ZodArray; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"plan">; + id: z$1.ZodString; + text: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"contextCompaction">; + id: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"backgroundTask">; + id: z$1.ZodString; + taskType: z$1.ZodString; + description: z$1.ZodString; + status: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + failed: "failed"; + interrupted: "interrupted"; + }>; + taskStatus: z$1.ZodEnum<{ + pending: "pending"; + running: "running"; + paused: "paused"; + completed: "completed"; + failed: "failed"; + killed: "killed"; + stopped: "stopped"; + }>; + skipTranscript: z$1.ZodBoolean; + workflowName: z$1.ZodOptional; + workflow: z$1.ZodOptional; + }, z$1.core.$strip>>; + agents: z$1.ZodArray; + model: z$1.ZodString; + attempt: z$1.ZodNumber; + cached: z$1.ZodBoolean; + lastProgressAt: z$1.ZodNumber; + phaseIndex: z$1.ZodOptional; + phaseTitle: z$1.ZodOptional; + agentType: z$1.ZodOptional; + isolation: z$1.ZodOptional; + queuedAt: z$1.ZodOptional; + startedAt: z$1.ZodOptional; + lastToolName: z$1.ZodOptional; + lastToolSummary: z$1.ZodOptional; + promptPreview: z$1.ZodOptional; + resultPreview: z$1.ZodOptional; + error: z$1.ZodOptional; + tokens: z$1.ZodOptional; + toolCalls: z$1.ZodOptional; + durationMs: z$1.ZodOptional; + }, z$1.core.$strip>>; + }, z$1.core.$strip>>; + usage: z$1.ZodOptional>; + summary: z$1.ZodOptional; + error: z$1.ZodOptional; + outputFile: z$1.ZodOptional; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>], "type">; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/completed">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + item: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + type: z$1.ZodLiteral<"userMessage">; + id: z$1.ZodString; + content: z$1.ZodArray; + text: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + }, z$1.core.$strip>], "type">>; + clientRequestId: z$1.ZodOptional; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strict>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"agentMessage">; + id: z$1.ZodString; + text: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"commandExecution">; + id: z$1.ZodString; + command: z$1.ZodString; + cwd: z$1.ZodString; + status: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + failed: "failed"; + interrupted: "interrupted"; + }>; + approvalStatus: z$1.ZodNullable>; + aggregatedOutput: z$1.ZodOptional; + exitCode: z$1.ZodOptional; + durationMs: z$1.ZodOptional; + truncation: z$1.ZodOptional>; + result: z$1.ZodOptional>; + resultText: z$1.ZodOptional>; + }, z$1.core.$strip>>; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"fileChange">; + id: z$1.ZodString; + changes: z$1.ZodArray; + movePath: z$1.ZodOptional; + diff: z$1.ZodOptional; + }, z$1.core.$strip>>; + status: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + failed: "failed"; + interrupted: "interrupted"; + }>; + approvalStatus: z$1.ZodNullable>; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"webSearch">; + id: z$1.ZodString; + queries: z$1.ZodArray; + resultText: z$1.ZodNullable; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"webFetch">; + id: z$1.ZodString; + url: z$1.ZodString; + prompt: z$1.ZodNullable; + pattern: z$1.ZodNullable; + resultText: z$1.ZodNullable; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"imageView">; + id: z$1.ZodString; + path: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"toolCall">; + id: z$1.ZodString; + server: z$1.ZodOptional; + tool: z$1.ZodString; + arguments: z$1.ZodOptional>; + status: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + failed: "failed"; + interrupted: "interrupted"; + }>; + result: z$1.ZodOptional; + error: z$1.ZodOptional; + durationMs: z$1.ZodOptional; + truncation: z$1.ZodOptional>; + result: z$1.ZodOptional>; + resultText: z$1.ZodOptional>; + }, z$1.core.$strip>>; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"reasoning">; + id: z$1.ZodString; + summary: z$1.ZodArray; + content: z$1.ZodArray; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"plan">; + id: z$1.ZodString; + text: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"contextCompaction">; + id: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"backgroundTask">; + id: z$1.ZodString; + taskType: z$1.ZodString; + description: z$1.ZodString; + status: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + failed: "failed"; + interrupted: "interrupted"; + }>; + taskStatus: z$1.ZodEnum<{ + pending: "pending"; + running: "running"; + paused: "paused"; + completed: "completed"; + failed: "failed"; + killed: "killed"; + stopped: "stopped"; + }>; + skipTranscript: z$1.ZodBoolean; + workflowName: z$1.ZodOptional; + workflow: z$1.ZodOptional; + }, z$1.core.$strip>>; + agents: z$1.ZodArray; + model: z$1.ZodString; + attempt: z$1.ZodNumber; + cached: z$1.ZodBoolean; + lastProgressAt: z$1.ZodNumber; + phaseIndex: z$1.ZodOptional; + phaseTitle: z$1.ZodOptional; + agentType: z$1.ZodOptional; + isolation: z$1.ZodOptional; + queuedAt: z$1.ZodOptional; + startedAt: z$1.ZodOptional; + lastToolName: z$1.ZodOptional; + lastToolSummary: z$1.ZodOptional; + promptPreview: z$1.ZodOptional; + resultPreview: z$1.ZodOptional; + error: z$1.ZodOptional; + tokens: z$1.ZodOptional; + toolCalls: z$1.ZodOptional; + durationMs: z$1.ZodOptional; + }, z$1.core.$strip>>; + }, z$1.core.$strip>>; + usage: z$1.ZodOptional>; + summary: z$1.ZodOptional; + error: z$1.ZodOptional; + outputFile: z$1.ZodOptional; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>], "type">; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/agentMessage/delta">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + itemId: z$1.ZodString; + delta: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/commandExecution/outputDelta">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + itemId: z$1.ZodString; + delta: z$1.ZodString; + reset: z$1.ZodOptional; + parentToolCallId: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/fileChange/outputDelta">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + itemId: z$1.ZodString; + delta: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/reasoning/summaryTextDelta">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + itemId: z$1.ZodString; + delta: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/reasoning/textDelta">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + itemId: z$1.ZodString; + delta: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/plan/delta">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + itemId: z$1.ZodString; + delta: z$1.ZodString; + parentToolCallId: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/mcpToolCall/progress">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + itemId: z$1.ZodString; + message: z$1.ZodOptional; + parentToolCallId: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/toolCall/progress">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + itemId: z$1.ZodString; + message: z$1.ZodOptional; + parentToolCallId: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/backgroundTask/progress">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + item: z$1.ZodObject<{ + type: z$1.ZodLiteral<"backgroundTask">; + id: z$1.ZodString; + taskType: z$1.ZodString; + description: z$1.ZodString; + status: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + failed: "failed"; + interrupted: "interrupted"; + }>; + taskStatus: z$1.ZodEnum<{ + pending: "pending"; + running: "running"; + paused: "paused"; + completed: "completed"; + failed: "failed"; + killed: "killed"; + stopped: "stopped"; + }>; + skipTranscript: z$1.ZodBoolean; + workflowName: z$1.ZodOptional; + workflow: z$1.ZodOptional; + }, z$1.core.$strip>>; + agents: z$1.ZodArray; + model: z$1.ZodString; + attempt: z$1.ZodNumber; + cached: z$1.ZodBoolean; + lastProgressAt: z$1.ZodNumber; + phaseIndex: z$1.ZodOptional; + phaseTitle: z$1.ZodOptional; + agentType: z$1.ZodOptional; + isolation: z$1.ZodOptional; + queuedAt: z$1.ZodOptional; + startedAt: z$1.ZodOptional; + lastToolName: z$1.ZodOptional; + lastToolSummary: z$1.ZodOptional; + promptPreview: z$1.ZodOptional; + resultPreview: z$1.ZodOptional; + error: z$1.ZodOptional; + tokens: z$1.ZodOptional; + toolCalls: z$1.ZodOptional; + durationMs: z$1.ZodOptional; + }, z$1.core.$strip>>; + }, z$1.core.$strip>>; + usage: z$1.ZodOptional>; + summary: z$1.ZodOptional; + error: z$1.ZodOptional; + outputFile: z$1.ZodOptional; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"item/backgroundTask/completed">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + item: z$1.ZodObject<{ + type: z$1.ZodLiteral<"backgroundTask">; + id: z$1.ZodString; + taskType: z$1.ZodString; + description: z$1.ZodString; + status: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + failed: "failed"; + interrupted: "interrupted"; + }>; + taskStatus: z$1.ZodEnum<{ + pending: "pending"; + running: "running"; + paused: "paused"; + completed: "completed"; + failed: "failed"; + killed: "killed"; + stopped: "stopped"; + }>; + skipTranscript: z$1.ZodBoolean; + workflowName: z$1.ZodOptional; + workflow: z$1.ZodOptional; + }, z$1.core.$strip>>; + agents: z$1.ZodArray; + model: z$1.ZodString; + attempt: z$1.ZodNumber; + cached: z$1.ZodBoolean; + lastProgressAt: z$1.ZodNumber; + phaseIndex: z$1.ZodOptional; + phaseTitle: z$1.ZodOptional; + agentType: z$1.ZodOptional; + isolation: z$1.ZodOptional; + queuedAt: z$1.ZodOptional; + startedAt: z$1.ZodOptional; + lastToolName: z$1.ZodOptional; + lastToolSummary: z$1.ZodOptional; + promptPreview: z$1.ZodOptional; + resultPreview: z$1.ZodOptional; + error: z$1.ZodOptional; + tokens: z$1.ZodOptional; + toolCalls: z$1.ZodOptional; + durationMs: z$1.ZodOptional; + }, z$1.core.$strip>>; + }, z$1.core.$strip>>; + usage: z$1.ZodOptional>; + summary: z$1.ZodOptional; + error: z$1.ZodOptional; + outputFile: z$1.ZodOptional; + parentToolCallId: z$1.ZodOptional; + }, z$1.core.$strip>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"thread/tokenUsage/updated">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + tokenUsage: z$1.ZodObject<{ + total: z$1.ZodObject<{ + totalTokens: z$1.ZodNumber; + inputTokens: z$1.ZodNumber; + cachedInputTokens: z$1.ZodNumber; + outputTokens: z$1.ZodNumber; + reasoningOutputTokens: z$1.ZodNumber; + }, z$1.core.$strip>; + last: z$1.ZodObject<{ + totalTokens: z$1.ZodNumber; + inputTokens: z$1.ZodNumber; + cachedInputTokens: z$1.ZodNumber; + outputTokens: z$1.ZodNumber; + reasoningOutputTokens: z$1.ZodNumber; + }, z$1.core.$strip>; + modelContextWindow: z$1.ZodNullable; + }, z$1.core.$strip>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"thread/contextWindowUsage/updated">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + contextWindowUsage: z$1.ZodObject<{ + usedTokens: z$1.ZodNullable; + modelContextWindow: z$1.ZodNullable; + estimated: z$1.ZodBoolean; + }, z$1.core.$strip>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"turn/plan/updated">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + plan: z$1.ZodArray>; + }, z$1.core.$strip>>; + explanation: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"turn/diff/updated">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + diff: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"provider/error">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + message: z$1.ZodString; + detail: z$1.ZodOptional; + willRetry: z$1.ZodOptional; + errorInfo: z$1.ZodOptional; + providerCode: z$1.ZodNullable; + httpStatusCode: z$1.ZodNullable; + }, z$1.core.$strip>>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"provider/warning">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + category: z$1.ZodEnum<{ + deprecation: "deprecation"; + config: "config"; + general: "general"; + }>; + summary: z$1.ZodOptional; + details: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"provider/modelFallback">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + originalModel: z$1.ZodString; + fallbackModel: z$1.ZodString; + reason: z$1.ZodEnum<{ + refusal: "refusal"; + provider: "provider"; + }>; + message: z$1.ZodString; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"provider/unhandled">; + threadId: z$1.ZodString; + providerThreadId: z$1.ZodString; + providerId: z$1.ZodString; + rawType: z$1.ZodString; + rawEvent: z$1.ZodObject<{ + jsonrpc: z$1.ZodLiteral<"2.0">; + id: z$1.ZodOptional>; + method: z$1.ZodString; + params: z$1.ZodOptional>>; + }, z$1.core.$strip>; + parentToolCallId: z$1.ZodOptional; +}, z$1.core.$strip>], "type">, z$1.ZodObject<{ + scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"turn">; + turnId: z$1.ZodString; + }, z$1.core.$strip>], "kind">; +}, z$1.core.$strip>>, z$1.ZodIntersection; + threadId: z$1.ZodString; + direction: z$1.ZodLiteral<"outbound">; + source: z$1.ZodEnum<{ + spawn: "spawn"; + tell: "tell"; + }>; + initiator: z$1.ZodEnum<{ + system: "system"; + user: "user"; + agent: "agent"; + }>; + request: z$1.ZodObject<{ + method: z$1.ZodEnum<{ + "thread/start": "thread/start"; + "turn/start": "turn/start"; + }>; + params: z$1.ZodRecord; + }, z$1.core.$strip>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"client/turn/requested">; + threadId: z$1.ZodString; + direction: z$1.ZodLiteral<"outbound">; + requestId: z$1.ZodString; + source: z$1.ZodEnum<{ + spawn: "spawn"; + tell: "tell"; + }>; + initiator: z$1.ZodEnum<{ + system: "system"; + user: "user"; + agent: "agent"; + }>; + senderThreadId: z$1.ZodNullable; + systemMessageKind: z$1.ZodOptional>; + systemMessageSubject: z$1.ZodOptional; + threadId: z$1.ZodString; + threadName: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread-batch">; + count: z$1.ZodNumber; + }, z$1.core.$strip>], "kind">>>; + input: z$1.ZodArray>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>; + inputGroups: z$1.ZodOptional>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>>>; + target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread-start">; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"new-turn">; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"auto">; + expectedTurnId: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"steer">; + expectedTurnId: z$1.ZodNullable; + }, z$1.core.$strip>], "kind">; + request: z$1.ZodObject<{ + method: z$1.ZodEnum<{ + "thread/start": "thread/start"; + "turn/start": "turn/start"; + }>; + params: z$1.ZodRecord; + }, z$1.core.$strip>; + execution: z$1.ZodObject<{ + seq: z$1.ZodOptional; + model: z$1.ZodString; + serviceTier: z$1.ZodEnum<{ + default: "default"; + fast: "fast"; + }>; + reasoningLevel: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + source: z$1.ZodEnum<{ + "client/thread/start": "client/thread/start"; + "client/turn/requested": "client/turn/requested"; + "client/turn/start": "client/turn/start"; + }>; + permissionMode: z$1.ZodEnum<{ + readonly: "readonly"; + full: "full"; + auto: "auto"; + "accept-edits": "accept-edits"; + "workspace-write": "workspace-write"; + }>; + }, z$1.core.$strip>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"client/turn/start">; + threadId: z$1.ZodString; + direction: z$1.ZodLiteral<"outbound">; + source: z$1.ZodEnum<{ + spawn: "spawn"; + tell: "tell"; + }>; + initiator: z$1.ZodEnum<{ + system: "system"; + user: "user"; + agent: "agent"; + }>; + request: z$1.ZodObject<{ + method: z$1.ZodEnum<{ + "thread/start": "thread/start"; + "turn/start": "turn/start"; + }>; + params: z$1.ZodRecord; + }, z$1.core.$strip>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"system/error">; + threadId: z$1.ZodString; + code: z$1.ZodOptional; + message: z$1.ZodString; + detail: z$1.ZodOptional; + reconnectAttempt: z$1.ZodOptional; + reconnectTotal: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"system/manager/user_message">; + threadId: z$1.ZodString; + text: z$1.ZodString; + toolCallId: z$1.ZodOptional; + turnId: z$1.ZodOptional; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"system/thread/interrupted">; + threadId: z$1.ZodString; + reason: z$1.ZodEnum<{ + "manual-stop": "manual-stop"; + "host-daemon-restarted": "host-daemon-restarted"; + "provider-turn-idle": "provider-turn-idle"; + }>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"system/operation">; + threadId: z$1.ZodString; + operation: z$1.ZodString; + status: z$1.ZodString; + message: z$1.ZodString; + operationId: z$1.ZodString; + metadata: z$1.ZodOptional>>>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"system/permissionGrant/lifecycle">; + threadId: z$1.ZodString; + interactionId: z$1.ZodString; + providerId: z$1.ZodString; + providerRequestId: z$1.ZodString; + status: z$1.ZodEnum<{ + pending: "pending"; + interrupted: "interrupted"; + resolving: "resolving"; + resolved: "resolved"; + }>; + resolution: z$1.ZodDefault; + grantedPermissions: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + decision: z$1.ZodLiteral<"allow_for_session">; + grantedPermissions: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + decision: z$1.ZodLiteral<"deny">; + }, z$1.core.$strip>], "decision">>>; + statusReason: z$1.ZodDefault>; + subject: z$1.ZodObject<{ + kind: z$1.ZodLiteral<"permission_grant">; + itemId: z$1.ZodString; + toolName: z$1.ZodNullable; + permissions: z$1.ZodObject<{ + network: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>; + }, z$1.core.$strip>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"system/userQuestion/lifecycle">; + threadId: z$1.ZodString; + interactionId: z$1.ZodString; + providerId: z$1.ZodString; + providerRequestId: z$1.ZodString; + status: z$1.ZodEnum<{ + pending: "pending"; + interrupted: "interrupted"; + resolving: "resolving"; + resolved: "resolved"; + }>; + resolution: z$1.ZodDefault; + answers: z$1.ZodRecord; + freeText: z$1.ZodOptional; + }, z$1.core.$strip>>; + }, z$1.core.$strip>>>; + statusReason: z$1.ZodDefault>; + payload: z$1.ZodObject<{ + kind: z$1.ZodLiteral<"user_question">; + questions: z$1.ZodArray; + multiSelect: z$1.ZodBoolean; + options: z$1.ZodOptional; + }, z$1.core.$strip>>>; + allowFreeText: z$1.ZodBoolean; + }, z$1.core.$strip>>; + }, z$1.core.$strip>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"system/thread-provisioning">; + threadId: z$1.ZodString; + provisioningId: z$1.ZodString; + status: z$1.ZodEnum<{ + completed: "completed"; + failed: "failed"; + active: "active"; + cancelled: "cancelled"; + }>; + environmentId: z$1.ZodString; + entries: z$1.ZodArray; + key: z$1.ZodString; + text: z$1.ZodString; + startedAt: z$1.ZodOptional; + status: z$1.ZodOptional>; + metadata: z$1.ZodOptional>; + }, z$1.core.$strip>>; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"system/provider-turn-watchdog">; + threadId: z$1.ZodString; + reason: z$1.ZodLiteral<"provider-turn-idle">; + thresholdMs: z$1.ZodNumber; + elapsedMs: z$1.ZodNumber; + activeTurnId: z$1.ZodString; + activeTurnStartedAt: z$1.ZodNumber; + lastActivityEventSequence: z$1.ZodNumber; + lastActivityEventType: z$1.ZodString; + lastActivityEventAt: z$1.ZodNumber; + providerId: z$1.ZodString; + providerThreadId: z$1.ZodNullable; + firedAt: z$1.ZodNumber; +}, z$1.core.$strip>]>, z$1.ZodObject<{ + scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"turn">; + turnId: z$1.ZodString; + }, z$1.core.$strip>], "kind">; +}, z$1.core.$strip>>]>>; +type ThreadEvent = z$1.infer; +type ThreadEventType = ThreadEvent["type"]; + +declare const providerInfoSchema: z$1.ZodObject<{ + id: z$1.ZodString; + displayName: z$1.ZodString; + logoUrl: z$1.ZodNullable; + capabilities: z$1.ZodObject<{ + supportsArchive: z$1.ZodBoolean; + supportsRename: z$1.ZodBoolean; + supportsServiceTier: z$1.ZodBoolean; + supportsUserQuestion: z$1.ZodBoolean; + supportsFork: z$1.ZodBoolean; + supportedPermissionModes: z$1.ZodArray>; + }, z$1.core.$strip>; + composerActions: z$1.ZodArray; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plan">; + command: z$1.ZodObject<{ + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + trailingText: z$1.ZodString; + }, z$1.core.$strip>; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"goal">; + command: z$1.ZodObject<{ + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + trailingText: z$1.ZodString; + }, z$1.core.$strip>; + }, z$1.core.$strip>], "kind">>; + available: z$1.ZodBoolean; +}, z$1.core.$strip>; +type ProviderInfo = z$1.infer; + +declare const threadEventScopeSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; +}, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"turn">; + turnId: z$1.ZodString; +}, z$1.core.$strip>], "kind">; +type ThreadEventScope = z$1.infer; + +type ThreadEventByType = { + [TType in ThreadEventType]: Extract; +}; +type ThreadEventForType = ThreadEventByType[TType]; +type StoredThreadEventDataFromEvent = Omit; +interface ThreadEventRowBase { + id: string; + scope: ThreadEventScope; + threadId: string; + seq: number; + createdAt: number; +} +type ThreadEventRowFromEvent = ThreadEventRowBase & { + type: TEvent["type"]; + data: StoredThreadEventDataFromEvent; +}; +type ThreadEventRowOfType = ThreadEventRowFromEvent>; +type ThreadEventRow = { + [TType in ThreadEventType]: ThreadEventRowOfType; +}[ThreadEventType]; + +declare const threadStatusSchema: z$1.ZodEnum<{ + error: "error"; + active: "active"; + starting: "starting"; + idle: "idle"; + stopping: "stopping"; +}>; +type ThreadStatus = z$1.infer; + +declare const threadTimelinePendingTodosSchema: z$1.ZodObject<{ + sourceSeq: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + items: z$1.ZodArray; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type ThreadTimelinePendingTodos = z$1.infer; + +declare const threadQueuedMessageSchema: z$1.ZodObject<{ + id: z$1.ZodString; + content: z$1.ZodArray>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>; + model: z$1.ZodString; + reasoningLevel: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + permissionMode: z$1.ZodEnum<{ + full: "full"; + auto: "auto"; + "accept-edits": "accept-edits"; + }>; + serviceTier: z$1.ZodEnum<{ + default: "default"; + fast: "fast"; + }>; + groupWithNext: z$1.ZodBoolean; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; +}, z$1.core.$strip>; +type ThreadQueuedMessage = z$1.infer; + +declare const workspaceFileListResponseSchema: z$1.ZodObject<{ + files: z$1.ZodArray>; + truncated: z$1.ZodBoolean; +}, z$1.core.$strip>; +type WorkspaceFileListResponse = z$1.infer; +declare const workspacePathListResponseSchema: z$1.ZodObject<{ + paths: z$1.ZodArray; + path: z$1.ZodString; + name: z$1.ZodString; + score: z$1.ZodNumber; + positions: z$1.ZodArray; + }, z$1.core.$strip>>; + truncated: z$1.ZodBoolean; +}, z$1.core.$strip>; +type WorkspacePathListResponse = z$1.infer; + +declare const createProjectSourceRequestSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + hostId: z$1.ZodString; + type: z$1.ZodLiteral<"local_path">; + path: z$1.ZodPipe>; +}, z$1.core.$strict>, z$1.ZodObject<{ + hostId: z$1.ZodString; + type: z$1.ZodLiteral<"clone">; + targetPath: z$1.ZodOptional>>; + remoteUrl: z$1.ZodOptional; +}, z$1.core.$strict>], "type">; +type CreateProjectSourceRequest = z$1.infer; +declare const createProjectRequestSchema: z$1.ZodObject<{ + name: z$1.ZodString; + source: z$1.ZodObject<{ + hostId: z$1.ZodString; + type: z$1.ZodLiteral<"local_path">; + path: z$1.ZodPipe>; + }, z$1.core.$strict>; +}, z$1.core.$strip>; +type CreateProjectRequest = z$1.infer; +declare const threadSectionSchema: z$1.ZodObject<{ + id: z$1.ZodString; + name: z$1.ZodString; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; +}, z$1.core.$strict>; +type ThreadSectionResponse = z$1.infer; +declare const createThreadSectionRequestSchema: z$1.ZodObject<{ + name: z$1.ZodString; +}, z$1.core.$strict>; +type CreateThreadSectionRequest = z$1.infer; +declare const updateThreadSectionRequestSchema: z$1.ZodObject<{ + id: z$1.ZodString; + name: z$1.ZodString; +}, z$1.core.$strict>; +type UpdateThreadSectionRequest = z$1.infer; +declare const deleteThreadSectionRequestSchema: z$1.ZodObject<{ + id: z$1.ZodString; +}, z$1.core.$strict>; +type DeleteThreadSectionRequest = z$1.infer; +declare const threadSectionMutationResponseSchema: z$1.ZodObject<{ + id: z$1.ZodString; + name: z$1.ZodString; + updatedThreadCount: z$1.ZodNumber; +}, z$1.core.$strict>; +type ThreadSectionMutationResponse = z$1.infer; +declare const reorderProjectRequestSchema: z$1.ZodObject<{ + previousProjectId: z$1.ZodNullable; + nextProjectId: z$1.ZodNullable; +}, z$1.core.$strip>; +type ReorderProjectRequest = z$1.infer; +declare const projectListQuerySchema: z$1.ZodObject<{ + include: z$1.ZodOptional; + includePersonal: z$1.ZodOptional>; +}, z$1.core.$strip>; +type ProjectListQuery = z$1.infer; +declare const projectFilesQuerySchema: z$1.ZodObject<{ + query: z$1.ZodOptional>; + limit: z$1.ZodOptional>; + hostId: z$1.ZodOptional; + environmentId: z$1.ZodOptional, z$1.ZodOptional>>; +}, z$1.core.$strip>; +type ProjectFilesQuery = z$1.infer; +declare const projectPathsQuerySchema: z$1.ZodObject<{ + query: z$1.ZodOptional>; + limit: z$1.ZodOptional>; + includeFiles: z$1.ZodEnum<{ + true: "true"; + false: "false"; + }>; + includeDirectories: z$1.ZodEnum<{ + true: "true"; + false: "false"; + }>; + hostId: z$1.ZodOptional; + environmentId: z$1.ZodOptional, z$1.ZodOptional>>; +}, z$1.core.$strip>; +type ProjectPathsQuery = z$1.infer; +declare const projectFileContentQuerySchema: z$1.ZodObject<{ + path: z$1.ZodString; + hostId: z$1.ZodOptional; + environmentId: z$1.ZodOptional, z$1.ZodOptional>>; +}, z$1.core.$strip>; +type ProjectFileContentQuery = z$1.infer; +declare const projectBranchesQuerySchema: z$1.ZodObject<{ + query: z$1.ZodOptional; + limit: z$1.ZodOptional; + hostId: z$1.ZodString; + selectedBranch: z$1.ZodOptional; +}, z$1.core.$strip>; +type ProjectBranchesQuery = z$1.infer; +declare const projectBranchesResponseSchema: z$1.ZodObject<{ + branches: z$1.ZodArray; + branchesTruncated: z$1.ZodBoolean; + checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"branch">; + branchName: z$1.ZodString; + headSha: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"detached">; + headSha: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"unborn">; + branchName: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"unknown">; + reason: z$1.ZodString; + }, z$1.core.$strip>], "kind">; + defaultBranch: z$1.ZodNullable; + defaultBranchRelation: z$1.ZodNullable>; + hasUncommittedChanges: z$1.ZodBoolean; + operation: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"none">; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"merge">; + hasConflicts: z$1.ZodBoolean; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"rebase">; + hasConflicts: z$1.ZodBoolean; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"cherry-pick">; + hasConflicts: z$1.ZodBoolean; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"revert">; + hasConflicts: z$1.ZodBoolean; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"unknown">; + reason: z$1.ZodString; + hasConflicts: z$1.ZodBoolean; + }, z$1.core.$strip>], "kind">; + originDefaultBranch: z$1.ZodNullable; + remoteBranches: z$1.ZodArray; + remoteBranchesTruncated: z$1.ZodBoolean; + selectedBranch: z$1.ZodNullable; + }, z$1.core.$strip>>; + defaultWorktreeBaseBranch: z$1.ZodNullable; +}, z$1.core.$strip>; +type ProjectBranchesResponse = z$1.infer; +declare const promptHistoryQuerySchema: z$1.ZodObject<{ + limit: z$1.ZodOptional; +}, z$1.core.$strip>; +type PromptHistoryQuery = z$1.infer; +declare const promptHistoryResponseSchema: z$1.ZodArray>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>; +}, z$1.core.$strip>>; +type PromptHistoryResponse = z$1.infer; +declare const updateProjectRequestSchema: z$1.ZodObject<{ + name: z$1.ZodOptional; +}, z$1.core.$strip>; +type UpdateProjectRequest = z$1.infer; +declare const updateProjectSourceRequestSchema: z$1.ZodObject<{ + type: z$1.ZodLiteral<"local_path">; + path: z$1.ZodOptional>>; + isDefault: z$1.ZodOptional>; +}, z$1.core.$strict>; +type UpdateProjectSourceRequest = z$1.infer; +declare const commandListResponseSchema: z$1.ZodObject<{ + commands: z$1.ZodArray; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + description: z$1.ZodNullable; + argumentHint: z$1.ZodNullable; + pluginId: z$1.ZodOptional; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type CommandListResponse = z$1.infer; +/** Query for the complete command catalog available to a project and provider. */ +declare const projectCommandsQuerySchema: z$1.ZodObject<{ + provider: z$1.ZodString; + hostId: z$1.ZodOptional; + environmentId: z$1.ZodOptional, z$1.ZodOptional>>; +}, z$1.core.$strict>; +type ProjectCommandsQuery = z$1.infer; +declare const projectResponseSchema: z$1.ZodObject<{ + id: z$1.ZodString; + kind: z$1.ZodEnum<{ + standard: "standard"; + personal: "personal"; + }>; + name: z$1.ZodString; + gitRemoteUrl: z$1.ZodNullable; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + sources: z$1.ZodArray; + hostId: z$1.ZodString; + path: z$1.ZodString; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type ProjectResponse = z$1.infer; +declare const projectWithThreadsResponseSchema: z$1.ZodObject<{ + id: z$1.ZodString; + kind: z$1.ZodEnum<{ + standard: "standard"; + personal: "personal"; + }>; + name: z$1.ZodString; + gitRemoteUrl: z$1.ZodNullable; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + sources: z$1.ZodArray; + hostId: z$1.ZodString; + path: z$1.ZodString; + }, z$1.core.$strip>>; + threads: z$1.ZodArray; + providerId: z$1.ZodString; + title: z$1.ZodNullable; + titleFallback: z$1.ZodNullable; + sectionId: z$1.ZodNullable; + status: z$1.ZodEnum<{ + error: "error"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + }>; + parentThreadId: z$1.ZodNullable; + sourceThreadId: z$1.ZodNullable; + originKind: z$1.ZodNullable>; + childOrigin: z$1.ZodNullable>; + originPluginId: z$1.ZodNullable; + visibility: z$1.ZodEnum<{ + visible: "visible"; + hidden: "hidden"; + }>; + archivedAt: z$1.ZodNullable; + pinnedAt: z$1.ZodNullable; + deletedAt: z$1.ZodNullable; + lastReadAt: z$1.ZodNullable; + latestAttentionAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + runtime: z$1.ZodObject<{ + displayStatus: z$1.ZodEnum<{ + error: "error"; + provisioning: "provisioning"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + "host-reconnecting": "host-reconnecting"; + "waiting-for-host": "waiting-for-host"; + }>; + hostReconnectGraceExpiresAt: z$1.ZodNullable; + }, z$1.core.$strip>; + activity: z$1.ZodObject<{ + activeWorkflowCount: z$1.ZodNumber; + activeBackgroundAgentCount: z$1.ZodNumber; + activeBackgroundCommandCount: z$1.ZodNumber; + activePlanModeCount: z$1.ZodNumber; + activeGoalCount: z$1.ZodNumber; + }, z$1.core.$strip>; + pinSortKey: z$1.ZodNullable; + hasPendingInteraction: z$1.ZodBoolean; + environmentHostId: z$1.ZodNullable; + environmentName: z$1.ZodNullable; + environmentBranchName: z$1.ZodNullable; + environmentWorkspaceDisplayKind: z$1.ZodEnum<{ + "managed-worktree": "managed-worktree"; + "unmanaged-worktree": "unmanaged-worktree"; + other: "other"; + }>; + }, z$1.core.$strip>>; + defaultExecutionOptions: z$1.ZodNullable; + reasoningLevel: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + permissionMode: z$1.ZodEnum<{ + "accept-edits": "accept-edits"; + auto: "auto"; + full: "full"; + }>; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type ProjectWithThreadsResponse = z$1.infer; +declare const uploadedPromptAttachmentSchema: z$1.ZodObject<{ + type: z$1.ZodEnum<{ + localImage: "localImage"; + localFile: "localFile"; + }>; + path: z$1.ZodString; + name: z$1.ZodString; + mimeType: z$1.ZodOptional; + sizeBytes: z$1.ZodNumber; +}, z$1.core.$strip>; +type UploadedPromptAttachment = z$1.infer; +declare const copyProjectAttachmentsRequestSchema: z$1.ZodObject<{ + sourceProjectId: z$1.ZodString; + paths: z$1.ZodArray; +}, z$1.core.$strict>; +type CopyProjectAttachmentsRequest = z$1.infer; + +declare const updateEnvironmentRequestSchema: z$1.ZodObject<{ + mergeBaseBranch: z$1.ZodOptional>; + name: z$1.ZodOptional>; +}, z$1.core.$strip>; +type UpdateEnvironmentRequest = z$1.infer; +/** + * Query for searching paths in an environment's workspace. Unlike the + * project-scoped variant this needs no `environmentId` — the environment is + * the route param — and is project-agnostic, so it works for projectless + * (personal) environments too. + */ +declare const environmentPathsQuerySchema: z$1.ZodObject<{ + query: z$1.ZodOptional; + limit: z$1.ZodOptional; + includeFiles: z$1.ZodEnum<{ + true: "true"; + false: "false"; + }>; + includeDirectories: z$1.ZodEnum<{ + true: "true"; + false: "false"; + }>; +}, z$1.core.$strip>; +type EnvironmentPathsQuery = z$1.infer; +declare const environmentDiffBranchesQuerySchema: z$1.ZodObject<{ + query: z$1.ZodOptional; + limit: z$1.ZodOptional; + selectedBranch: z$1.ZodOptional; +}, z$1.core.$strip>; +type EnvironmentDiffBranchesQuery = z$1.infer; +declare const environmentDiffBranchesResponseSchema: z$1.ZodObject<{ + branches: z$1.ZodArray; + branchesTruncated: z$1.ZodBoolean; + remoteBranches: z$1.ZodArray; + remoteBranchesTruncated: z$1.ZodBoolean; + selectedBranch: z$1.ZodNullable; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type EnvironmentDiffBranchesResponse = z$1.infer; +declare const environmentStatusQuerySchema: z$1.ZodObject<{ + mergeBaseBranch: z$1.ZodOptional>; +}, z$1.core.$strip>; +type EnvironmentStatusQuery = z$1.infer; +declare const environmentDiffQuerySchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + target: z$1.ZodLiteral<"uncommitted">; +}, z$1.core.$strip>, z$1.ZodObject<{ + target: z$1.ZodLiteral<"branch_committed">; + mergeBaseBranch: z$1.ZodPipe; +}, z$1.core.$strip>, z$1.ZodObject<{ + target: z$1.ZodLiteral<"all">; + mergeBaseBranch: z$1.ZodPipe; +}, z$1.core.$strip>, z$1.ZodObject<{ + target: z$1.ZodLiteral<"commit">; + sha: z$1.ZodString; +}, z$1.core.$strip>], "target">; +type EnvironmentDiffQuery = z$1.infer; +/** + * Query for fetching a single file's contents at one side of a diff target. + * Used by the diff card to reparse the card's patch with full old/new contents + * so `@pierre/diffs` can render expand-context buttons between hunks. + * + * For `branch_committed` / `all`, callers pass the resolved merge-base SHA + * (`mergeBaseRef`, surfaced by `workspace.diff`) rather than the branch name + * — the diff itself was computed against that SHA, so reading the old side + * from the same SHA keeps the file content aligned with the hunk line + * numbers. Reading from the branch tip is wrong whenever the branch has + * moved past the merge-base since the file existed there. + */ +declare const environmentDiffFileQuerySchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + target: z$1.ZodLiteral<"uncommitted">; + path: z$1.ZodString; + side: z$1.ZodEnum<{ + new: "new"; + old: "old"; + }>; +}, z$1.core.$strip>, z$1.ZodObject<{ + target: z$1.ZodLiteral<"branch_committed">; + mergeBaseRef: z$1.ZodString; + path: z$1.ZodString; + side: z$1.ZodEnum<{ + new: "new"; + old: "old"; + }>; +}, z$1.core.$strip>, z$1.ZodObject<{ + target: z$1.ZodLiteral<"all">; + mergeBaseRef: z$1.ZodString; + path: z$1.ZodString; + side: z$1.ZodEnum<{ + new: "new"; + old: "old"; + }>; +}, z$1.core.$strip>, z$1.ZodObject<{ + target: z$1.ZodLiteral<"commit">; + sha: z$1.ZodString; + path: z$1.ZodString; + side: z$1.ZodEnum<{ + new: "new"; + old: "old"; + }>; +}, z$1.core.$strip>], "target">; +type EnvironmentDiffFileQuery = z$1.infer; +declare const environmentDiffFileResponseSchema: z$1.ZodObject<{ + path: z$1.ZodString; + content: z$1.ZodString; + contentEncoding: z$1.ZodEnum<{ + utf8: "utf8"; + base64: "base64"; + }>; + mimeType: z$1.ZodOptional; + sizeBytes: z$1.ZodNumber; +}, z$1.core.$strip>; +type EnvironmentDiffFileResponse = z$1.infer; +declare const environmentArchiveThreadsResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; + archivedThreadIds: z$1.ZodArray; +}, z$1.core.$strip>; +type EnvironmentArchiveThreadsResponse = z$1.infer; +declare const pullRequestMergeMethodSchema: z$1.ZodEnum<{ + merge: "merge"; + rebase: "rebase"; + squash: "squash"; +}>; +type PullRequestMergeMethod = z$1.infer; +declare const commitActionResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; + action: z$1.ZodLiteral<"commit">; + message: z$1.ZodString; + commitSha: z$1.ZodString; + commitSubject: z$1.ZodString; +}, z$1.core.$strip>; +type CommitActionResponse = z$1.infer; +declare const squashMergeActionResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; + action: z$1.ZodLiteral<"squash_merge">; + merged: z$1.ZodBoolean; + message: z$1.ZodString; + commitSha: z$1.ZodString; + commitSubject: z$1.ZodString; +}, z$1.core.$strip>; +type SquashMergeActionResponse = z$1.infer; +declare const pullRequestReadyActionResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; + action: z$1.ZodLiteral<"pull_request_ready">; + message: z$1.ZodString; +}, z$1.core.$strip>; +type PullRequestReadyActionResponse = z$1.infer; +declare const pullRequestMergeActionResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; + action: z$1.ZodLiteral<"pull_request_merge">; + method: z$1.ZodEnum<{ + merge: "merge"; + rebase: "rebase"; + squash: "squash"; + }>; + message: z$1.ZodString; +}, z$1.core.$strip>; +type PullRequestMergeActionResponse = z$1.infer; +declare const pullRequestDraftActionResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; + action: z$1.ZodLiteral<"pull_request_draft">; + message: z$1.ZodString; +}, z$1.core.$strip>; +type PullRequestDraftActionResponse = z$1.infer; +declare const environmentStatusResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"available">; + workspace: z$1.ZodObject<{ + workingTree: z$1.ZodObject<{ + insertions: z$1.ZodNumber; + deletions: z$1.ZodNumber; + files: z$1.ZodArray; + insertions: z$1.ZodNullable; + deletions: z$1.ZodNullable; + }, z$1.core.$strip>>; + hasUncommittedChanges: z$1.ZodBoolean; + state: z$1.ZodEnum<{ + clean: "clean"; + untracked: "untracked"; + dirty_uncommitted: "dirty_uncommitted"; + committed_unmerged: "committed_unmerged"; + dirty_and_committed_unmerged: "dirty_and_committed_unmerged"; + }>; + }, z$1.core.$strip>; + checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"branch">; + branchName: z$1.ZodString; + headSha: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"detached">; + headSha: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"unborn">; + branchName: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"unknown">; + reason: z$1.ZodString; + }, z$1.core.$strip>], "kind">; + branch: z$1.ZodObject<{ + currentBranch: z$1.ZodNullable; + defaultBranch: z$1.ZodString; + }, z$1.core.$strip>; + mergeBase: z$1.ZodNullable; + insertions: z$1.ZodNullable; + deletions: z$1.ZodNullable; + }, z$1.core.$strip>>; + mergeBaseBranch: z$1.ZodString; + baseRef: z$1.ZodNullable; + aheadCount: z$1.ZodNumber; + behindCount: z$1.ZodNumber; + hasCommittedUnmergedChanges: z$1.ZodBoolean; + commits: z$1.ZodArray>; + }, z$1.core.$strip>>; + }, z$1.core.$strip>; +}, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"not_applicable">; + reason: z$1.ZodEnum<{ + non_git_environment: "non_git_environment"; + }>; + message: z$1.ZodString; +}, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"unavailable">; + failure: z$1.ZodObject<{ + code: z$1.ZodEnum<{ + unknown: "unknown"; + path_not_found: "path_not_found"; + not_git_repo: "not_git_repo"; + not_worktree: "not_worktree"; + workspace_type_mismatch: "workspace_type_mismatch"; + permission_denied: "permission_denied"; + unknown_environment: "unknown_environment"; + }>; + workspacePath: z$1.ZodString; + message: z$1.ZodString; + }, z$1.core.$strict>; +}, z$1.core.$strict>], "outcome">; +/** + * Structured pull-request lookup outcome. "absent" is a real answer — the + * host checked and the branch has no PR (non-git environments resolve to + * "absent" without a daemon call). "unavailable" means the lookup itself + * failed (gh missing, not authenticated, timeout, unreachable workspace), so + * callers must not render it as "no PR exists". + */ +declare const environmentPullRequestResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"available">; + pullRequest: z$1.ZodObject<{ + number: z$1.ZodNumber; + title: z$1.ZodString; + state: z$1.ZodEnum<{ + merged: "merged"; + draft: "draft"; + open: "open"; + closed: "closed"; + }>; + url: z$1.ZodString; + baseRefName: z$1.ZodString; + headRefName: z$1.ZodString; + updatedAt: z$1.ZodString; + checks: z$1.ZodObject<{ + state: z$1.ZodEnum<{ + unknown: "unknown"; + pending: "pending"; + passing: "passing"; + failing: "failing"; + no_checks: "no_checks"; + }>; + totalCount: z$1.ZodNumber; + passedCount: z$1.ZodNumber; + failedCount: z$1.ZodNumber; + pendingCount: z$1.ZodNumber; + }, z$1.core.$strict>; + review: z$1.ZodObject<{ + state: z$1.ZodEnum<{ + none: "none"; + approved: "approved"; + changes_requested: "changes_requested"; + review_required: "review_required"; + review_requested: "review_requested"; + }>; + reviewRequestCount: z$1.ZodNumber; + }, z$1.core.$strict>; + mergeability: z$1.ZodObject<{ + state: z$1.ZodEnum<{ + unknown: "unknown"; + draft: "draft"; + mergeable: "mergeable"; + conflicts: "conflicts"; + blocked: "blocked"; + }>; + mergeStateStatus: z$1.ZodNullable>; + mergeable: z$1.ZodNullable>; + }, z$1.core.$strict>; + attention: z$1.ZodEnum<{ + none: "none"; + merged: "merged"; + draft: "draft"; + closed: "closed"; + changes_requested: "changes_requested"; + review_requested: "review_requested"; + conflicts: "conflicts"; + blocked: "blocked"; + checks_failed: "checks_failed"; + checks_pending: "checks_pending"; + ready_to_merge: "ready_to_merge"; + }>; + }, z$1.core.$strict>; +}, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"absent">; +}, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"unavailable">; + message: z$1.ZodString; +}, z$1.core.$strict>], "outcome">; +type EnvironmentPullRequestResponse = z$1.infer; +declare const environmentDiffResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"available">; + diff: z$1.ZodObject<{ + diff: z$1.ZodString; + truncated: z$1.ZodBoolean; + shortstat: z$1.ZodString; + files: z$1.ZodString; + mergeBaseRef: z$1.ZodNullable; + }, z$1.core.$strip>; +}, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"not_applicable">; + reason: z$1.ZodEnum<{ + non_git_environment: "non_git_environment"; + }>; + message: z$1.ZodString; +}, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"unavailable">; + failure: z$1.ZodObject<{ + code: z$1.ZodEnum<{ + unknown: "unknown"; + path_not_found: "path_not_found"; + not_git_repo: "not_git_repo"; + not_worktree: "not_worktree"; + workspace_type_mismatch: "workspace_type_mismatch"; + permission_denied: "permission_denied"; + unknown_environment: "unknown_environment"; + }>; + workspacePath: z$1.ZodString; + message: z$1.ZodString; + }, z$1.core.$strict>; +}, z$1.core.$strict>], "outcome">; +type EnvironmentDiffResponse = z$1.infer; +declare const environmentDiffFilesResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"available">; + files: z$1.ZodArray; + changeKind: z$1.ZodEnum<{ + deleted: "deleted"; + added: "added"; + modified: "modified"; + renamed: "renamed"; + copied: "copied"; + type_changed: "type_changed"; + }>; + additions: z$1.ZodNumber; + deletions: z$1.ZodNumber; + binary: z$1.ZodBoolean; + origin: z$1.ZodEnum<{ + untracked: "untracked"; + tracked: "tracked"; + }>; + loadMode: z$1.ZodEnum<{ + auto: "auto"; + on_demand: "on_demand"; + too_large: "too_large"; + }>; + }, z$1.core.$strip>>; + shortstat: z$1.ZodString; + mergeBaseRef: z$1.ZodNullable; + initialPatches: z$1.ZodArray>; +}, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"not_applicable">; + reason: z$1.ZodEnum<{ + non_git_environment: "non_git_environment"; + too_many_files: "too_many_files"; + }>; + message: z$1.ZodString; +}, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"unavailable">; + failure: z$1.ZodObject<{ + code: z$1.ZodEnum<{ + unknown: "unknown"; + path_not_found: "path_not_found"; + not_git_repo: "not_git_repo"; + not_worktree: "not_worktree"; + workspace_type_mismatch: "workspace_type_mismatch"; + permission_denied: "permission_denied"; + unknown_environment: "unknown_environment"; + }>; + workspacePath: z$1.ZodString; + message: z$1.ZodString; + }, z$1.core.$strict>; +}, z$1.core.$strict>], "outcome">; +type EnvironmentDiffFilesResponse = z$1.infer; +declare const environmentDiffPatchResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"available">; + patches: z$1.ZodArray>; +}, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"not_applicable">; + reason: z$1.ZodEnum<{ + non_git_environment: "non_git_environment"; + }>; + message: z$1.ZodString; +}, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"unavailable">; + failure: z$1.ZodObject<{ + code: z$1.ZodEnum<{ + unknown: "unknown"; + path_not_found: "path_not_found"; + not_git_repo: "not_git_repo"; + not_worktree: "not_worktree"; + workspace_type_mismatch: "workspace_type_mismatch"; + permission_denied: "permission_denied"; + unknown_environment: "unknown_environment"; + }>; + workspacePath: z$1.ZodString; + message: z$1.ZodString; + }, z$1.core.$strict>; +}, z$1.core.$strict>], "outcome">; +type EnvironmentDiffPatchResponse = z$1.infer; +/** + * Body for `POST /diff/patch`: the diff target plus the list of new paths whose + * patches the client wants. A POST (not GET) because the repeated `paths` array + * cannot survive flat query parsing. The client supplies only new paths; the + * server re-derives each file's rename/copy pairing (`previousPath`) from its + * own TOC. + */ +declare const environmentDiffPatchRequestSchema: z$1.ZodObject<{ + target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + type: z$1.ZodLiteral<"uncommitted">; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"branch_committed">; + mergeBaseBranch: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"all">; + mergeBaseBranch: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"commit">; + sha: z$1.ZodString; + }, z$1.core.$strip>], "type">; + paths: z$1.ZodArray; +}, z$1.core.$strict>; +type EnvironmentDiffPatchRequest = z$1.infer; +type EnvironmentStatusResponse = z$1.infer; + +declare const providerUsageResponseSchema: z$1.ZodObject<{ + codex: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + status: z$1.ZodLiteral<"ok">; + accountEmail: z$1.ZodNullable; + planLabel: z$1.ZodNullable; + windows: z$1.ZodArray; + cost: z$1.ZodOptional>; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"not_installed">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"unauthenticated">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"expired">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"error">; + message: z$1.ZodString; + }, z$1.core.$strip>], "status">; + claudeCode: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + status: z$1.ZodLiteral<"ok">; + accountEmail: z$1.ZodNullable; + planLabel: z$1.ZodNullable; + windows: z$1.ZodArray; + cost: z$1.ZodOptional>; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"not_installed">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"unauthenticated">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"expired">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"error">; + message: z$1.ZodString; + }, z$1.core.$strip>], "status">; + cursor: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + status: z$1.ZodLiteral<"ok">; + accountEmail: z$1.ZodNullable; + planLabel: z$1.ZodNullable; + windows: z$1.ZodArray; + cost: z$1.ZodOptional>; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"not_installed">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"unauthenticated">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"expired">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"error">; + message: z$1.ZodString; + }, z$1.core.$strip>], "status">; +}, z$1.core.$strip>; +type ProviderUsageResponse = z$1.infer; +type HostDaemonCommandTransport = "settled" | "onlineRpc"; +type HostDaemonCommandEnvironmentLane = "read" | "write"; +type HostDaemonFlushEventsBeforeResult = boolean | "when-initiated"; +interface HostDaemonCommandDescriptor { + type: Type; + schema: Schema; + resultSchema: ResultSchema; + transport: Transport; + retryable: Retryable; + flushEventsBeforeResult: HostDaemonFlushEventsBeforeResult; + envLane: HostDaemonCommandEnvironmentLane | null; +} +declare const hostDaemonCommandRegistry: { + "thread.start": HostDaemonCommandDescriptor<"thread.start", z$1.ZodObject<{ + environmentId: z$1.ZodString; + threadId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + projectId: z$1.ZodString; + providerId: z$1.ZodString; + acpLaunchSpec: z$1.ZodOptional; + env: z$1.ZodRecord; + cwd: z$1.ZodOptional; + modelCli: z$1.ZodOptional; + selectFlag: z$1.ZodOptional; + primaryModels: z$1.ZodArray; + }, z$1.core.$strict>, z$1.ZodTransform<{ + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + } | undefined, { + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + }>>>; + reasoningCli: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + nativeReasoning: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + permissionCli: z$1.ZodOptional>; + workspaceWrite: z$1.ZodOptional>; + readonly: z$1.ZodOptional>; + insertAfterArgs: z$1.ZodOptional; + }, z$1.core.$strict>>; + }, z$1.core.$strict>>; + options: z$1.ZodIntersection; + reasoningLevel: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + claudeCodePermissionMode: z$1.ZodOptional>; + claudeCodeMockCliTraffic: z$1.ZodOptional>; + workflowsEnabled: z$1.ZodBoolean; + memoryEnabled: z$1.ZodOptional; + providerSubagentsEnabled: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + permissionMode: z$1.ZodLiteral<"accept-edits">; + permissionScope: z$1.ZodLiteral<"workspace">; + approvalReviewer: z$1.ZodLiteral<"user">; + permissionEscalation: z$1.ZodEnum<{ + ask: "ask"; + deny: "deny"; + }>; + }, z$1.core.$strip>, z$1.ZodObject<{ + permissionMode: z$1.ZodLiteral<"auto">; + permissionScope: z$1.ZodLiteral<"workspace">; + approvalReviewer: z$1.ZodLiteral<"automatic">; + permissionEscalation: z$1.ZodEnum<{ + ask: "ask"; + deny: "deny"; + }>; + }, z$1.core.$strip>, z$1.ZodObject<{ + permissionMode: z$1.ZodLiteral<"full">; + permissionScope: z$1.ZodLiteral<"full">; + approvalReviewer: z$1.ZodNull; + permissionEscalation: z$1.ZodNull; + }, z$1.core.$strip>], "permissionMode">>; + instructions: z$1.ZodString; + dynamicTools: z$1.ZodArray>; + injectedSkillSources: z$1.ZodArray; + treeHash: z$1.ZodString; + entryPath: z$1.ZodString; + sourceType: z$1.ZodEnum<{ + builtin: "builtin"; + "data-dir": "data-dir"; + }>; + }, z$1.core.$strict>, z$1.ZodObject<{ + name: z$1.ZodString; + description: z$1.ZodString; + kind: z$1.ZodLiteral<"workspace-path">; + sourceType: z$1.ZodLiteral<"project">; + sourceRootPath: z$1.ZodString; + skillFilePath: z$1.ZodString; + }, z$1.core.$strict>], "kind">>; + disallowedTools: z$1.ZodOptional>; + instructionMode: z$1.ZodEnum<{ + append: "append"; + replace: "replace"; + }>; + type: z$1.ZodLiteral<"thread.start">; + requestId: z$1.ZodString; + input: z$1.ZodArray>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + builtin: "builtin"; + project: "project"; + user: "user"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>; + inputGroups: z$1.ZodOptional>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + builtin: "builtin"; + project: "project"; + user: "user"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>>>; + threadStoragePath: z$1.ZodOptional; + fork: z$1.ZodOptional>; + }, z$1.core.$strict>, z$1.ZodObject<{ + providerThreadId: z$1.ZodString; + }, z$1.core.$strip>, "settled", false>; + "turn.submit": HostDaemonCommandDescriptor<"turn.submit", z$1.ZodObject<{ + environmentId: z$1.ZodString; + threadId: z$1.ZodString; + type: z$1.ZodLiteral<"turn.submit">; + requestId: z$1.ZodString; + input: z$1.ZodArray>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + builtin: "builtin"; + project: "project"; + user: "user"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>; + inputGroups: z$1.ZodOptional>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + builtin: "builtin"; + project: "project"; + user: "user"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>>>; + options: z$1.ZodIntersection; + reasoningLevel: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + claudeCodePermissionMode: z$1.ZodOptional>; + claudeCodeMockCliTraffic: z$1.ZodOptional>; + workflowsEnabled: z$1.ZodBoolean; + memoryEnabled: z$1.ZodOptional; + providerSubagentsEnabled: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + permissionMode: z$1.ZodLiteral<"accept-edits">; + permissionScope: z$1.ZodLiteral<"workspace">; + approvalReviewer: z$1.ZodLiteral<"user">; + permissionEscalation: z$1.ZodEnum<{ + ask: "ask"; + deny: "deny"; + }>; + }, z$1.core.$strip>, z$1.ZodObject<{ + permissionMode: z$1.ZodLiteral<"auto">; + permissionScope: z$1.ZodLiteral<"workspace">; + approvalReviewer: z$1.ZodLiteral<"automatic">; + permissionEscalation: z$1.ZodEnum<{ + ask: "ask"; + deny: "deny"; + }>; + }, z$1.core.$strip>, z$1.ZodObject<{ + permissionMode: z$1.ZodLiteral<"full">; + permissionScope: z$1.ZodLiteral<"full">; + approvalReviewer: z$1.ZodNull; + permissionEscalation: z$1.ZodNull; + }, z$1.core.$strip>], "permissionMode">>; + acpLaunchSpec: z$1.ZodOptional; + env: z$1.ZodRecord; + cwd: z$1.ZodOptional; + modelCli: z$1.ZodOptional; + selectFlag: z$1.ZodOptional; + primaryModels: z$1.ZodArray; + }, z$1.core.$strict>, z$1.ZodTransform<{ + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + } | undefined, { + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + }>>>; + reasoningCli: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + nativeReasoning: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + permissionCli: z$1.ZodOptional>; + workspaceWrite: z$1.ZodOptional>; + readonly: z$1.ZodOptional>; + insertAfterArgs: z$1.ZodOptional; + }, z$1.core.$strict>>; + }, z$1.core.$strict>>; + resumeContext: z$1.ZodObject<{ + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + instructionMode: z$1.ZodEnum<{ + append: "append"; + replace: "replace"; + }>; + projectId: z$1.ZodString; + providerId: z$1.ZodString; + acpLaunchSpec: z$1.ZodOptional; + env: z$1.ZodRecord; + cwd: z$1.ZodOptional; + modelCli: z$1.ZodOptional; + selectFlag: z$1.ZodOptional; + primaryModels: z$1.ZodArray; + }, z$1.core.$strict>, z$1.ZodTransform<{ + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + } | undefined, { + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + }>>>; + reasoningCli: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + nativeReasoning: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + permissionCli: z$1.ZodOptional>; + workspaceWrite: z$1.ZodOptional>; + readonly: z$1.ZodOptional>; + insertAfterArgs: z$1.ZodOptional; + }, z$1.core.$strict>>; + }, z$1.core.$strict>>; + instructions: z$1.ZodString; + dynamicTools: z$1.ZodArray>; + injectedSkillSources: z$1.ZodArray; + treeHash: z$1.ZodString; + entryPath: z$1.ZodString; + sourceType: z$1.ZodEnum<{ + builtin: "builtin"; + "data-dir": "data-dir"; + }>; + }, z$1.core.$strict>, z$1.ZodObject<{ + name: z$1.ZodString; + description: z$1.ZodString; + kind: z$1.ZodLiteral<"workspace-path">; + sourceType: z$1.ZodLiteral<"project">; + sourceRootPath: z$1.ZodString; + skillFilePath: z$1.ZodString; + }, z$1.core.$strict>], "kind">>; + disallowedTools: z$1.ZodOptional>; + providerThreadId: z$1.ZodString; + }, z$1.core.$strict>; + target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + mode: z$1.ZodLiteral<"start">; + }, z$1.core.$strip>, z$1.ZodObject<{ + mode: z$1.ZodLiteral<"auto">; + expectedTurnId: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + mode: z$1.ZodLiteral<"steer">; + expectedTurnId: z$1.ZodNullable; + }, z$1.core.$strip>], "mode">; + }, z$1.core.$strict>, z$1.ZodObject<{ + appliedAs: z$1.ZodEnum<{ + steer: "steer"; + "new-turn": "new-turn"; + }>; + }, z$1.core.$strip>, "settled", false>; + "thread.stop": HostDaemonCommandDescriptor<"thread.stop", z$1.ZodObject<{ + environmentId: z$1.ZodString; + threadId: z$1.ZodString; + type: z$1.ZodLiteral<"thread.stop">; + }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, "settled", false>; + "thread.goal.clear": HostDaemonCommandDescriptor<"thread.goal.clear", z$1.ZodObject<{ + environmentId: z$1.ZodString; + threadId: z$1.ZodString; + type: z$1.ZodLiteral<"thread.goal.clear">; + options: z$1.ZodIntersection; + reasoningLevel: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + claudeCodePermissionMode: z$1.ZodOptional>; + claudeCodeMockCliTraffic: z$1.ZodOptional>; + workflowsEnabled: z$1.ZodBoolean; + memoryEnabled: z$1.ZodOptional; + providerSubagentsEnabled: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + permissionMode: z$1.ZodLiteral<"accept-edits">; + permissionScope: z$1.ZodLiteral<"workspace">; + approvalReviewer: z$1.ZodLiteral<"user">; + permissionEscalation: z$1.ZodEnum<{ + ask: "ask"; + deny: "deny"; + }>; + }, z$1.core.$strip>, z$1.ZodObject<{ + permissionMode: z$1.ZodLiteral<"auto">; + permissionScope: z$1.ZodLiteral<"workspace">; + approvalReviewer: z$1.ZodLiteral<"automatic">; + permissionEscalation: z$1.ZodEnum<{ + ask: "ask"; + deny: "deny"; + }>; + }, z$1.core.$strip>, z$1.ZodObject<{ + permissionMode: z$1.ZodLiteral<"full">; + permissionScope: z$1.ZodLiteral<"full">; + approvalReviewer: z$1.ZodNull; + permissionEscalation: z$1.ZodNull; + }, z$1.core.$strip>], "permissionMode">>; + acpLaunchSpec: z$1.ZodOptional; + env: z$1.ZodRecord; + cwd: z$1.ZodOptional; + modelCli: z$1.ZodOptional; + selectFlag: z$1.ZodOptional; + primaryModels: z$1.ZodArray; + }, z$1.core.$strict>, z$1.ZodTransform<{ + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + } | undefined, { + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + }>>>; + reasoningCli: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + nativeReasoning: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + permissionCli: z$1.ZodOptional>; + workspaceWrite: z$1.ZodOptional>; + readonly: z$1.ZodOptional>; + insertAfterArgs: z$1.ZodOptional; + }, z$1.core.$strict>>; + }, z$1.core.$strict>>; + resumeContext: z$1.ZodObject<{ + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + instructionMode: z$1.ZodEnum<{ + append: "append"; + replace: "replace"; + }>; + projectId: z$1.ZodString; + providerId: z$1.ZodString; + acpLaunchSpec: z$1.ZodOptional; + env: z$1.ZodRecord; + cwd: z$1.ZodOptional; + modelCli: z$1.ZodOptional; + selectFlag: z$1.ZodOptional; + primaryModels: z$1.ZodArray; + }, z$1.core.$strict>, z$1.ZodTransform<{ + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + } | undefined, { + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + }>>>; + reasoningCli: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + nativeReasoning: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + permissionCli: z$1.ZodOptional>; + workspaceWrite: z$1.ZodOptional>; + readonly: z$1.ZodOptional>; + insertAfterArgs: z$1.ZodOptional; + }, z$1.core.$strict>>; + }, z$1.core.$strict>>; + instructions: z$1.ZodString; + dynamicTools: z$1.ZodArray>; + injectedSkillSources: z$1.ZodArray; + treeHash: z$1.ZodString; + entryPath: z$1.ZodString; + sourceType: z$1.ZodEnum<{ + builtin: "builtin"; + "data-dir": "data-dir"; + }>; + }, z$1.core.$strict>, z$1.ZodObject<{ + name: z$1.ZodString; + description: z$1.ZodString; + kind: z$1.ZodLiteral<"workspace-path">; + sourceType: z$1.ZodLiteral<"project">; + sourceRootPath: z$1.ZodString; + skillFilePath: z$1.ZodString; + }, z$1.core.$strict>], "kind">>; + disallowedTools: z$1.ZodOptional>; + providerThreadId: z$1.ZodString; + }, z$1.core.$strict>; + }, z$1.core.$strict>, z$1.ZodObject<{ + cleared: z$1.ZodBoolean; + }, z$1.core.$strict>, "settled", false>; + "thread.plan.cancel": HostDaemonCommandDescriptor<"thread.plan.cancel", z$1.ZodObject<{ + environmentId: z$1.ZodString; + threadId: z$1.ZodString; + type: z$1.ZodLiteral<"thread.plan.cancel">; + expectedTurnId: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + cancelled: z$1.ZodBoolean; + }, z$1.core.$strict>, "settled", false>; + "thread.rename": HostDaemonCommandDescriptor<"thread.rename", z$1.ZodObject<{ + environmentId: z$1.ZodString; + threadId: z$1.ZodString; + type: z$1.ZodLiteral<"thread.rename">; + title: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, "settled", false>; + "thread.archive": HostDaemonCommandDescriptor<"thread.archive", z$1.ZodObject<{ + environmentId: z$1.ZodString; + threadId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"thread.archive">; + providerId: z$1.ZodString; + providerThreadId: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, "settled", false>; + "thread.unarchive": HostDaemonCommandDescriptor<"thread.unarchive", z$1.ZodObject<{ + environmentId: z$1.ZodString; + threadId: z$1.ZodString; + type: z$1.ZodLiteral<"thread.unarchive">; + providerId: z$1.ZodString; + providerThreadId: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, "settled", false>; + "interactive.resolve": HostDaemonCommandDescriptor<"interactive.resolve", z$1.ZodObject<{ + environmentId: z$1.ZodString; + threadId: z$1.ZodString; + type: z$1.ZodLiteral<"interactive.resolve">; + interactionId: z$1.ZodString; + providerId: z$1.ZodString; + providerThreadId: z$1.ZodString; + providerRequestId: z$1.ZodString; + resolution: z$1.ZodUnion; + grantedPermissions: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + decision: z$1.ZodLiteral<"allow_for_session">; + grantedPermissions: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + decision: z$1.ZodLiteral<"deny">; + }, z$1.core.$strip>], "decision">, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"user_answer">; + answers: z$1.ZodRecord; + freeText: z$1.ZodOptional; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin_submitted">; + }, z$1.core.$strip>]>; + }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, "settled", false>; + "codex.inference.complete": HostDaemonCommandDescriptor<"codex.inference.complete", z$1.ZodObject<{ + type: z$1.ZodLiteral<"codex.inference.complete">; + model: z$1.ZodString; + prompt: z$1.ZodString; + outputSchema: z$1.ZodType>; + timeoutMs: z$1.ZodNumber; + }, z$1.core.$strict>, z$1.ZodObject<{ + model: z$1.ZodString; + value: z$1.ZodType>; + }, z$1.core.$strip>, "settled", false>; + "codex.voice.transcribe": HostDaemonCommandDescriptor<"codex.voice.transcribe", z$1.ZodObject<{ + type: z$1.ZodLiteral<"codex.voice.transcribe">; + model: z$1.ZodString; + audioBase64: z$1.ZodString; + mimeType: z$1.ZodString; + filename: z$1.ZodString; + prompt: z$1.ZodNullable; + timeoutMs: z$1.ZodNumber; + }, z$1.core.$strict>, z$1.ZodObject<{ + model: z$1.ZodString; + text: z$1.ZodString; + }, z$1.core.$strip>, "settled", false>; + "environment.provision": HostDaemonCommandDescriptor<"environment.provision", z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + environmentId: z$1.ZodString; + type: z$1.ZodLiteral<"environment.provision">; + initiator: z$1.ZodNullable>; + workspaceProvisionType: z$1.ZodLiteral<"unmanaged">; + path: z$1.ZodString; + checkout: z$1.ZodOptional; + name: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"new">; + name: z$1.ZodString; + baseBranch: z$1.ZodString; + }, z$1.core.$strict>], "kind">>; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodString; + type: z$1.ZodLiteral<"environment.provision">; + initiator: z$1.ZodNullable>; + sourcePath: z$1.ZodString; + targetPath: z$1.ZodString; + branchName: z$1.ZodString; + baseBranch: z$1.ZodNullable; + setupTimeoutMs: z$1.ZodNumber; + workspaceProvisionType: z$1.ZodLiteral<"managed-worktree">; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodString; + type: z$1.ZodLiteral<"environment.provision">; + initiator: z$1.ZodNullable>; + workspaceProvisionType: z$1.ZodLiteral<"personal">; + targetPath: z$1.ZodString; + }, z$1.core.$strict>], "workspaceProvisionType">, z$1.ZodObject<{ + path: z$1.ZodString; + isGitRepo: z$1.ZodBoolean; + isWorktree: z$1.ZodBoolean; + branchName: z$1.ZodNullable; + defaultBranch: z$1.ZodNullable; + transcript: z$1.ZodArray; + key: z$1.ZodString; + text: z$1.ZodString; + startedAt: z$1.ZodOptional; + status: z$1.ZodOptional>; + metadata: z$1.ZodOptional>; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, "settled", false>; + "project.clone": HostDaemonCommandDescriptor<"project.clone", z$1.ZodObject<{ + type: z$1.ZodLiteral<"project.clone">; + remoteUrl: z$1.ZodString; + projectSlug: z$1.ZodString; + targetPath: z$1.ZodOptional; + }, z$1.core.$strict>, z$1.ZodObject<{ + path: z$1.ZodString; + gitRemoteUrl: z$1.ZodNullable; + }, z$1.core.$strict>, "settled", false>; + "environment.provision.cancel": HostDaemonCommandDescriptor<"environment.provision.cancel", z$1.ZodObject<{ + environmentId: z$1.ZodString; + type: z$1.ZodLiteral<"environment.provision.cancel">; + }, z$1.core.$strict>, z$1.ZodObject<{ + aborted: z$1.ZodBoolean; + }, z$1.core.$strip>, "settled", false>; + "environment.destroy": HostDaemonCommandDescriptor<"environment.destroy", z$1.ZodObject<{ + environmentId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"environment.destroy">; + }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, "settled", false>; + "workspace.commit": HostDaemonCommandDescriptor<"workspace.commit", z$1.ZodObject<{ + environmentId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"workspace.commit">; + message: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + commitSha: z$1.ZodString; + commitSubject: z$1.ZodString; + }, z$1.core.$strip>, "settled", false>; + "workspace.squash_merge": HostDaemonCommandDescriptor<"workspace.squash_merge", z$1.ZodObject<{ + environmentId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"workspace.squash_merge">; + targetBranch: z$1.ZodString; + commitMessage: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + commitSha: z$1.ZodString; + commitSubject: z$1.ZodString; + merged: z$1.ZodBoolean; + }, z$1.core.$strip>, "settled", false>; + "workspace.pull_request_action": HostDaemonCommandDescriptor<"workspace.pull_request_action", z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + environmentId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"workspace.pull_request_action">; + operation: z$1.ZodLiteral<"ready">; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"workspace.pull_request_action">; + operation: z$1.ZodLiteral<"draft">; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"workspace.pull_request_action">; + operation: z$1.ZodLiteral<"merge">; + method: z$1.ZodEnum<{ + merge: "merge"; + squash: "squash"; + rebase: "rebase"; + }>; + }, z$1.core.$strict>], "operation">, z$1.ZodObject<{}, z$1.core.$strict>, "settled", false>; + "host.list_files": HostDaemonCommandDescriptor<"host.list_files", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.list_files">; + path: z$1.ZodString; + query: z$1.ZodOptional; + limit: z$1.ZodNumber; + }, z$1.core.$strip>, z$1.ZodObject<{ + files: z$1.ZodArray>; + truncated: z$1.ZodBoolean; + }, z$1.core.$strip>, "onlineRpc", true>; + "host.list_paths": HostDaemonCommandDescriptor<"host.list_paths", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.list_paths">; + path: z$1.ZodString; + query: z$1.ZodOptional; + limit: z$1.ZodNumber; + includeFiles: z$1.ZodBoolean; + includeDirectories: z$1.ZodBoolean; + }, z$1.core.$strip>, z$1.ZodObject<{ + paths: z$1.ZodArray; + path: z$1.ZodString; + name: z$1.ZodString; + score: z$1.ZodNumber; + positions: z$1.ZodArray; + }, z$1.core.$strip>>; + truncated: z$1.ZodBoolean; + }, z$1.core.$strip>, "onlineRpc", true>; + "host.mkdir": HostDaemonCommandDescriptor<"host.mkdir", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.mkdir">; + path: z$1.ZodString; + rootPath: z$1.ZodOptional; + recursive: z$1.ZodBoolean; + }, z$1.core.$strict>, z$1.ZodObject<{ + ok: z$1.ZodLiteral; + }, z$1.core.$strict>, "onlineRpc", false>; + "host.move_path": HostDaemonCommandDescriptor<"host.move_path", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.move_path">; + sourcePath: z$1.ZodString; + destinationPath: z$1.ZodString; + rootPath: z$1.ZodOptional; + }, z$1.core.$strict>, z$1.ZodObject<{ + ok: z$1.ZodLiteral; + }, z$1.core.$strict>, "onlineRpc", false>; + "host.remove_path": HostDaemonCommandDescriptor<"host.remove_path", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.remove_path">; + path: z$1.ZodString; + rootPath: z$1.ZodOptional; + recursive: z$1.ZodBoolean; + }, z$1.core.$strict>, z$1.ZodObject<{ + ok: z$1.ZodLiteral; + }, z$1.core.$strict>, "onlineRpc", false>; + "host.browse_directory": HostDaemonCommandDescriptor<"host.browse_directory", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.browse_directory">; + path: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + directory: z$1.ZodString; + parent: z$1.ZodNullable; + entries: z$1.ZodArray; + name: z$1.ZodString; + path: z$1.ZodString; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, "onlineRpc", true>; + "host.paths_exist": HostDaemonCommandDescriptor<"host.paths_exist", z$1.ZodObject<{ + paths: z$1.ZodPipe, z$1.ZodTransform>; + type: z$1.ZodLiteral<"host.paths_exist">; + }, z$1.core.$strict>, z$1.ZodObject<{ + existence: z$1.ZodRecord; + }, z$1.core.$strip>, "onlineRpc", true>; + "project.inspect": HostDaemonCommandDescriptor<"project.inspect", z$1.ZodObject<{ + type: z$1.ZodLiteral<"project.inspect">; + path: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + path: z$1.ZodString; + gitRemoteUrl: z$1.ZodNullable; + }, z$1.core.$strict>, "onlineRpc", true>; + "project.clone_default_path": HostDaemonCommandDescriptor<"project.clone_default_path", z$1.ZodObject<{ + type: z$1.ZodLiteral<"project.clone_default_path">; + projectSlug: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + path: z$1.ZodString; + }, z$1.core.$strict>, "onlineRpc", true>; + "host.pick_folder": HostDaemonCommandDescriptor<"host.pick_folder", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.pick_folder">; + }, z$1.core.$strict>, z$1.ZodObject<{ + path: z$1.ZodNullable; + }, z$1.core.$strip>, "onlineRpc", false>; + "host.caffeinate": HostDaemonCommandDescriptor<"host.caffeinate", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.caffeinate">; + enabled: z$1.ZodBoolean; + }, z$1.core.$strict>, z$1.ZodObject<{ + enabled: z$1.ZodBoolean; + supported: z$1.ZodBoolean; + }, z$1.core.$strict>, "onlineRpc", false>; + "connect-tunnel.ensure-identity": HostDaemonCommandDescriptor<"connect-tunnel.ensure-identity", z$1.ZodObject<{ + type: z$1.ZodLiteral<"connect-tunnel.ensure-identity">; + }, z$1.core.$strict>, z$1.ZodObject<{ + label: z$1.ZodString; + baseDomain: z$1.ZodString; + }, z$1.core.$strict>, "onlineRpc", true>; + "host.list_commands": HostDaemonCommandDescriptor<"host.list_commands", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.list_commands">; + providerId: z$1.ZodString; + cwd: z$1.ZodNullable; + }, z$1.core.$strict>, z$1.ZodObject<{ + commands: z$1.ZodArray; + origin: z$1.ZodEnum<{ + project: "project"; + user: "user"; + }>; + description: z$1.ZodNullable; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, "onlineRpc", true>; + "host.list_branches": HostDaemonCommandDescriptor<"host.list_branches", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.list_branches">; + path: z$1.ZodString; + query: z$1.ZodOptional; + selectedBranch: z$1.ZodOptional; + limit: z$1.ZodNumber; + }, z$1.core.$strip>, z$1.ZodObject<{ + branches: z$1.ZodArray; + branchesTruncated: z$1.ZodBoolean; + checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"branch">; + branchName: z$1.ZodString; + headSha: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"detached">; + headSha: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"unborn">; + branchName: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"unknown">; + reason: z$1.ZodString; + }, z$1.core.$strip>], "kind">; + defaultBranch: z$1.ZodNullable; + defaultBranchRelation: z$1.ZodNullable>; + hasUncommittedChanges: z$1.ZodBoolean; + operation: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"none">; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"merge">; + hasConflicts: z$1.ZodBoolean; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"rebase">; + hasConflicts: z$1.ZodBoolean; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"cherry-pick">; + hasConflicts: z$1.ZodBoolean; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"revert">; + hasConflicts: z$1.ZodBoolean; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"unknown">; + reason: z$1.ZodString; + hasConflicts: z$1.ZodBoolean; + }, z$1.core.$strip>], "kind">; + originDefaultBranch: z$1.ZodNullable; + remoteBranches: z$1.ZodArray; + remoteBranchesTruncated: z$1.ZodBoolean; + selectedBranch: z$1.ZodNullable; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, "onlineRpc", true>; + "host.file_metadata": HostDaemonCommandDescriptor<"host.file_metadata", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.file_metadata">; + path: z$1.ZodString; + rootPath: z$1.ZodOptional; + }, z$1.core.$strict>, z$1.ZodObject<{ + path: z$1.ZodString; + modifiedAtMs: z$1.ZodNumber; + sizeBytes: z$1.ZodNumber; + }, z$1.core.$strip>, "onlineRpc", true>; + "host.read_file": HostDaemonCommandDescriptor<"host.read_file", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.read_file">; + path: z$1.ZodString; + rootPath: z$1.ZodOptional; + ref: z$1.ZodOptional; + }, z$1.core.$strip>, z$1.ZodObject<{ + path: z$1.ZodString; + content: z$1.ZodString; + contentEncoding: z$1.ZodEnum<{ + base64: "base64"; + utf8: "utf8"; + }>; + mimeType: z$1.ZodOptional; + sizeBytes: z$1.ZodNumber; + modifiedAtMs: z$1.ZodOptional; + sha256: z$1.ZodString; + }, z$1.core.$strip>, "onlineRpc", true>; + "host.read_file_relative": HostDaemonCommandDescriptor<"host.read_file_relative", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.read_file_relative">; + rootPath: z$1.ZodString; + path: z$1.ZodString; + dotfiles: z$1.ZodEnum<{ + deny: "deny"; + allow: "allow"; + }>; + }, z$1.core.$strict>, z$1.ZodObject<{ + path: z$1.ZodString; + content: z$1.ZodString; + contentEncoding: z$1.ZodEnum<{ + base64: "base64"; + utf8: "utf8"; + }>; + mimeType: z$1.ZodOptional; + sizeBytes: z$1.ZodNumber; + modifiedAtMs: z$1.ZodOptional; + sha256: z$1.ZodString; + }, z$1.core.$strip>, "onlineRpc", true>; + "host.write_file": HostDaemonCommandDescriptor<"host.write_file", z$1.ZodObject<{ + type: z$1.ZodLiteral<"host.write_file">; + path: z$1.ZodString; + rootPath: z$1.ZodOptional; + content: z$1.ZodString; + contentEncoding: z$1.ZodEnum<{ + base64: "base64"; + utf8: "utf8"; + }>; + createParents: z$1.ZodBoolean; + expectedSha256: z$1.ZodOptional>; + mode: z$1.ZodOptional; + }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"written">; + sha256: z$1.ZodString; + sizeBytes: z$1.ZodNumber; + }, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"conflict">; + currentSha256: z$1.ZodNullable; + }, z$1.core.$strict>], "outcome">, "onlineRpc", false>; + "provider.list_models": HostDaemonCommandDescriptor<"provider.list_models", z$1.ZodObject<{ + type: z$1.ZodLiteral<"provider.list_models">; + providerId: z$1.ZodString; + acpLaunchSpec: z$1.ZodOptional; + env: z$1.ZodRecord; + cwd: z$1.ZodOptional; + modelCli: z$1.ZodOptional; + selectFlag: z$1.ZodOptional; + primaryModels: z$1.ZodArray; + }, z$1.core.$strict>, z$1.ZodTransform<{ + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + } | undefined, { + listArgs: string[]; + primaryModels: string[]; + selectFlag?: string | undefined; + }>>>; + reasoningCli: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + nativeReasoning: z$1.ZodOptional>; + levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>; + defaultLevel: z$1.ZodOptional>; + }, z$1.core.$strict>>; + permissionCli: z$1.ZodOptional>; + workspaceWrite: z$1.ZodOptional>; + readonly: z$1.ZodOptional>; + insertAfterArgs: z$1.ZodOptional; + }, z$1.core.$strict>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + models: z$1.ZodArray; + description: z$1.ZodString; + }, z$1.core.$strip>>; + defaultReasoningEffort: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + isDefault: z$1.ZodBoolean; + }, z$1.core.$strip>>; + selectedOnlyModels: z$1.ZodArray; + description: z$1.ZodString; + }, z$1.core.$strip>>; + defaultReasoningEffort: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + isDefault: z$1.ZodBoolean; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, "onlineRpc", true>; + "known_acp_agents.status": HostDaemonCommandDescriptor<"known_acp_agents.status", z$1.ZodObject<{ + type: z$1.ZodLiteral<"known_acp_agents.status">; + agents: z$1.ZodArray>; + }, z$1.core.$strict>, z$1.ZodObject<{ + agents: z$1.ZodArray; + }, z$1.core.$strict>>; + }, z$1.core.$strict>, "onlineRpc", true>; + "provider.usage": HostDaemonCommandDescriptor<"provider.usage", z$1.ZodObject<{ + type: z$1.ZodLiteral<"provider.usage">; + }, z$1.core.$strict>, z$1.ZodObject<{ + codex: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + status: z$1.ZodLiteral<"ok">; + accountEmail: z$1.ZodNullable; + planLabel: z$1.ZodNullable; + windows: z$1.ZodArray; + cost: z$1.ZodOptional>; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"not_installed">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"unauthenticated">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"expired">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"error">; + message: z$1.ZodString; + }, z$1.core.$strip>], "status">; + claudeCode: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + status: z$1.ZodLiteral<"ok">; + accountEmail: z$1.ZodNullable; + planLabel: z$1.ZodNullable; + windows: z$1.ZodArray; + cost: z$1.ZodOptional>; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"not_installed">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"unauthenticated">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"expired">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"error">; + message: z$1.ZodString; + }, z$1.core.$strip>], "status">; + cursor: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + status: z$1.ZodLiteral<"ok">; + accountEmail: z$1.ZodNullable; + planLabel: z$1.ZodNullable; + windows: z$1.ZodArray; + cost: z$1.ZodOptional>; + }, z$1.core.$strip>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"not_installed">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"unauthenticated">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"expired">; + }, z$1.core.$strip>, z$1.ZodObject<{ + status: z$1.ZodLiteral<"error">; + message: z$1.ZodString; + }, z$1.core.$strip>], "status">; + }, z$1.core.$strip>, "onlineRpc", true>; + "provider_cli.status": HostDaemonCommandDescriptor<"provider_cli.status", z$1.ZodObject<{ + type: z$1.ZodLiteral<"provider_cli.status">; + }, z$1.core.$strict>, z$1.ZodRecord, z$1.ZodObject<{ + displayName: z$1.ZodString; + executableName: z$1.ZodString; + executablePath: z$1.ZodNullable; + installed: z$1.ZodBoolean; + installSource: z$1.ZodEnum<{ + external: "external"; + notInstalled: "notInstalled"; + npmGlobal: "npmGlobal"; + }>; + currentVersion: z$1.ZodNullable; + latestVersion: z$1.ZodNullable; + minimumSupportedVersion: z$1.ZodNullable; + npmPackageName: z$1.ZodNullable; + npmGlobalPackageVersion: z$1.ZodNullable; + installAction: z$1.ZodNullable; + label: z$1.ZodEnum<{ + Install: "Install"; + Update: "Update"; + }>; + commandKind: z$1.ZodEnum<{ + exec: "exec"; + shell: "shell"; + }>; + command: z$1.ZodString; + }, z$1.core.$strip>>; + needsUpdate: z$1.ZodBoolean; + versionUnsupported: z$1.ZodBoolean; + }, z$1.core.$strip>>, "onlineRpc", true>; + "provider_cli.install": HostDaemonCommandDescriptor<"provider_cli.install", z$1.ZodObject<{ + provider: z$1.ZodEnum<{ + codex: "codex"; + claudeCode: "claudeCode"; + cursor: "cursor"; + }>; + actionKind: z$1.ZodEnum<{ + install: "install"; + update: "update"; + }>; + type: z$1.ZodLiteral<"provider_cli.install">; + }, z$1.core.$strict>, z$1.ZodObject<{ + events: z$1.ZodArray; + provider: z$1.ZodEnum<{ + codex: "codex"; + claudeCode: "claudeCode"; + cursor: "cursor"; + }>; + command: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"output">; + provider: z$1.ZodEnum<{ + codex: "codex"; + claudeCode: "claudeCode"; + cursor: "cursor"; + }>; + stream: z$1.ZodEnum<{ + stdout: "stdout"; + stderr: "stderr"; + }>; + text: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"completed">; + provider: z$1.ZodEnum<{ + codex: "codex"; + claudeCode: "claudeCode"; + cursor: "cursor"; + }>; + exitCode: z$1.ZodNullable; + signal: z$1.ZodNullable; + success: z$1.ZodBoolean; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"error">; + provider: z$1.ZodEnum<{ + codex: "codex"; + claudeCode: "claudeCode"; + cursor: "cursor"; + }>; + message: z$1.ZodString; + }, z$1.core.$strip>], "type">>; + }, z$1.core.$strict>, "onlineRpc", false>; + "workspace.status": HostDaemonCommandDescriptor<"workspace.status", z$1.ZodObject<{ + environmentId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"workspace.status">; + mergeBaseBranch: z$1.ZodOptional; + }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"available">; + workspaceStatus: z$1.ZodObject<{ + workingTree: z$1.ZodObject<{ + insertions: z$1.ZodNumber; + deletions: z$1.ZodNumber; + files: z$1.ZodArray; + insertions: z$1.ZodNullable; + deletions: z$1.ZodNullable; + }, z$1.core.$strip>>; + hasUncommittedChanges: z$1.ZodBoolean; + state: z$1.ZodEnum<{ + clean: "clean"; + untracked: "untracked"; + dirty_uncommitted: "dirty_uncommitted"; + committed_unmerged: "committed_unmerged"; + dirty_and_committed_unmerged: "dirty_and_committed_unmerged"; + }>; + }, z$1.core.$strip>; + checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"branch">; + branchName: z$1.ZodString; + headSha: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"detached">; + headSha: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"unborn">; + branchName: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"unknown">; + reason: z$1.ZodString; + }, z$1.core.$strip>], "kind">; + branch: z$1.ZodObject<{ + currentBranch: z$1.ZodNullable; + defaultBranch: z$1.ZodString; + }, z$1.core.$strip>; + mergeBase: z$1.ZodNullable; + insertions: z$1.ZodNullable; + deletions: z$1.ZodNullable; + }, z$1.core.$strip>>; + mergeBaseBranch: z$1.ZodString; + baseRef: z$1.ZodNullable; + aheadCount: z$1.ZodNumber; + behindCount: z$1.ZodNumber; + hasCommittedUnmergedChanges: z$1.ZodBoolean; + commits: z$1.ZodArray>; + }, z$1.core.$strip>>; + }, z$1.core.$strip>; + }, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"unavailable">; + failure: z$1.ZodObject<{ + code: z$1.ZodEnum<{ + path_not_found: "path_not_found"; + not_git_repo: "not_git_repo"; + not_worktree: "not_worktree"; + workspace_type_mismatch: "workspace_type_mismatch"; + permission_denied: "permission_denied"; + unknown_environment: "unknown_environment"; + unknown: "unknown"; + }>; + workspacePath: z$1.ZodString; + message: z$1.ZodString; + }, z$1.core.$strict>; + }, z$1.core.$strict>], "outcome">, "onlineRpc", true>; + "workspace.diff": HostDaemonCommandDescriptor<"workspace.diff", z$1.ZodObject<{ + environmentId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"workspace.diff">; + target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + type: z$1.ZodLiteral<"uncommitted">; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"branch_committed">; + mergeBaseBranch: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"all">; + mergeBaseBranch: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"commit">; + sha: z$1.ZodString; + }, z$1.core.$strip>], "type">; + maxDiffBytes: z$1.ZodNumber; + maxFileListBytes: z$1.ZodNumber; + }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"available">; + diff: z$1.ZodObject<{ + diff: z$1.ZodString; + truncated: z$1.ZodBoolean; + shortstat: z$1.ZodString; + files: z$1.ZodString; + mergeBaseRef: z$1.ZodNullable; + }, z$1.core.$strip>; + }, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"unavailable">; + failure: z$1.ZodObject<{ + code: z$1.ZodEnum<{ + path_not_found: "path_not_found"; + not_git_repo: "not_git_repo"; + not_worktree: "not_worktree"; + workspace_type_mismatch: "workspace_type_mismatch"; + permission_denied: "permission_denied"; + unknown_environment: "unknown_environment"; + unknown: "unknown"; + }>; + workspacePath: z$1.ZodString; + message: z$1.ZodString; + }, z$1.core.$strict>; + }, z$1.core.$strict>], "outcome">, "onlineRpc", true>; + "workspace.diffFiles": HostDaemonCommandDescriptor<"workspace.diffFiles", z$1.ZodObject<{ + environmentId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"workspace.diffFiles">; + target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + type: z$1.ZodLiteral<"uncommitted">; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"branch_committed">; + mergeBaseBranch: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"all">; + mergeBaseBranch: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"commit">; + sha: z$1.ZodString; + }, z$1.core.$strip>], "type">; + }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"available">; + files: z$1.ZodArray; + statusLetter: z$1.ZodEnum<{ + M: "M"; + A: "A"; + D: "D"; + R: "R"; + C: "C"; + T: "T"; + }>; + additions: z$1.ZodNumber; + deletions: z$1.ZodNumber; + binary: z$1.ZodBoolean; + origin: z$1.ZodEnum<{ + untracked: "untracked"; + tracked: "tracked"; + }>; + }, z$1.core.$strip>>; + shortstat: z$1.ZodString; + mergeBaseRef: z$1.ZodNullable; + }, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"unavailable">; + failure: z$1.ZodObject<{ + code: z$1.ZodEnum<{ + path_not_found: "path_not_found"; + not_git_repo: "not_git_repo"; + not_worktree: "not_worktree"; + workspace_type_mismatch: "workspace_type_mismatch"; + permission_denied: "permission_denied"; + unknown_environment: "unknown_environment"; + unknown: "unknown"; + }>; + workspacePath: z$1.ZodString; + message: z$1.ZodString; + }, z$1.core.$strict>; + }, z$1.core.$strict>], "outcome">, "onlineRpc", true>; + "workspace.diffPatch": HostDaemonCommandDescriptor<"workspace.diffPatch", z$1.ZodObject<{ + environmentId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"workspace.diffPatch">; + target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + type: z$1.ZodLiteral<"uncommitted">; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"branch_committed">; + mergeBaseBranch: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"all">; + mergeBaseBranch: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"commit">; + sha: z$1.ZodString; + }, z$1.core.$strip>], "type">; + paths: z$1.ZodArray; + maxBytesPerFile: z$1.ZodNumber; + }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"available">; + patches: z$1.ZodArray>; + }, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"unavailable">; + failure: z$1.ZodObject<{ + code: z$1.ZodEnum<{ + path_not_found: "path_not_found"; + not_git_repo: "not_git_repo"; + not_worktree: "not_worktree"; + workspace_type_mismatch: "workspace_type_mismatch"; + permission_denied: "permission_denied"; + unknown_environment: "unknown_environment"; + unknown: "unknown"; + }>; + workspacePath: z$1.ZodString; + message: z$1.ZodString; + }, z$1.core.$strict>; + }, z$1.core.$strict>], "outcome">, "onlineRpc", true>; + "workspace.pull_request": HostDaemonCommandDescriptor<"workspace.pull_request", z$1.ZodObject<{ + environmentId: z$1.ZodString; + workspaceContext: z$1.ZodObject<{ + workspacePath: z$1.ZodString; + workspaceProvisionType: z$1.ZodEnum<{ + unmanaged: "unmanaged"; + "managed-worktree": "managed-worktree"; + personal: "personal"; + }>; + }, z$1.core.$strip>; + type: z$1.ZodLiteral<"workspace.pull_request">; + }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"available">; + pullRequest: z$1.ZodObject<{ + number: z$1.ZodNumber; + title: z$1.ZodString; + state: z$1.ZodEnum<{ + OPEN: "OPEN"; + CLOSED: "CLOSED"; + MERGED: "MERGED"; + }>; + url: z$1.ZodString; + isDraft: z$1.ZodBoolean; + baseRefName: z$1.ZodString; + headRefName: z$1.ZodString; + updatedAt: z$1.ZodString; + checks: z$1.ZodArray; + conclusion: z$1.ZodNullable>; + url: z$1.ZodNullable; + }, z$1.core.$strict>>; + reviewDecision: z$1.ZodNullable>; + reviewRequestCount: z$1.ZodNumber; + mergeStateStatus: z$1.ZodNullable>; + mergeable: z$1.ZodNullable>; + }, z$1.core.$strict>; + }, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"absent">; + }, z$1.core.$strict>, z$1.ZodObject<{ + outcome: z$1.ZodLiteral<"unavailable">; + message: z$1.ZodString; + }, z$1.core.$strict>], "outcome">, "onlineRpc", true>; +}; +type HostDaemonCommandRegistry = typeof hostDaemonCommandRegistry; +type AnyHostDaemonCommandDescriptor = HostDaemonCommandRegistry[keyof HostDaemonCommandRegistry]; +type HostDaemonCommandDescriptorForTransport = Extract; +type HostDaemonResultSchemaMapForTransport = { + [Descriptor in HostDaemonCommandDescriptorForTransport as Descriptor["type"]]: Descriptor["resultSchema"]; +}; +type HostDaemonOnlineRpcResultSchemaMap = HostDaemonResultSchemaMapForTransport<"onlineRpc">; +type HostDaemonOnlineRpcResultByType = { + [K in keyof HostDaemonOnlineRpcResultSchemaMap]: z$1.infer; +}; + +declare const pickFolderResponseSchema: z$1.ZodObject<{ + path: z$1.ZodNullable; +}, z$1.core.$strip>; +type PickFolderResponse = z$1.infer; +declare const pathsExistRequestSchema: z$1.ZodObject<{ + paths: z$1.ZodPipe, z$1.ZodTransform>; +}, z$1.core.$strip>; +type PathsExistRequest = z$1.infer; +declare const pathsExistResponseSchema: z$1.ZodObject<{ + existence: z$1.ZodRecord; +}, z$1.core.$strip>; +type PathsExistResponse = z$1.infer; +declare const providerCliStatusResponseSchema: z$1.ZodRecord, z$1.ZodObject<{ + displayName: z$1.ZodString; + executableName: z$1.ZodString; + executablePath: z$1.ZodNullable; + installed: z$1.ZodBoolean; + installSource: z$1.ZodEnum<{ + external: "external"; + notInstalled: "notInstalled"; + npmGlobal: "npmGlobal"; + }>; + currentVersion: z$1.ZodNullable; + latestVersion: z$1.ZodNullable; + minimumSupportedVersion: z$1.ZodNullable; + npmPackageName: z$1.ZodNullable; + npmGlobalPackageVersion: z$1.ZodNullable; + installAction: z$1.ZodNullable; + label: z$1.ZodEnum<{ + Install: "Install"; + Update: "Update"; + }>; + commandKind: z$1.ZodEnum<{ + exec: "exec"; + shell: "shell"; + }>; + command: z$1.ZodString; + }, z$1.core.$strip>>; + needsUpdate: z$1.ZodBoolean; + versionUnsupported: z$1.ZodBoolean; +}, z$1.core.$strip>>; +type ProviderCliStatusResponse = z$1.infer; +declare const providerCliInstallRequestSchema: z$1.ZodObject<{ + provider: z$1.ZodEnum<{ + codex: "codex"; + claudeCode: "claudeCode"; + cursor: "cursor"; + }>; + actionKind: z$1.ZodEnum<{ + install: "install"; + update: "update"; + }>; +}, z$1.core.$strip>; +type ProviderCliInstallRequest = z$1.infer; +declare const providerCliInstallEventSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + type: z$1.ZodLiteral<"started">; + provider: z$1.ZodEnum<{ + codex: "codex"; + claudeCode: "claudeCode"; + cursor: "cursor"; + }>; + command: z$1.ZodString; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"output">; + provider: z$1.ZodEnum<{ + codex: "codex"; + claudeCode: "claudeCode"; + cursor: "cursor"; + }>; + stream: z$1.ZodEnum<{ + stdout: "stdout"; + stderr: "stderr"; + }>; + text: z$1.ZodString; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"completed">; + provider: z$1.ZodEnum<{ + codex: "codex"; + claudeCode: "claudeCode"; + cursor: "cursor"; + }>; + exitCode: z$1.ZodNullable; + signal: z$1.ZodNullable; + success: z$1.ZodBoolean; +}, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"error">; + provider: z$1.ZodEnum<{ + codex: "codex"; + claudeCode: "claudeCode"; + cursor: "cursor"; + }>; + message: z$1.ZodString; +}, z$1.core.$strip>], "type">; +type ProviderCliInstallEvent = z$1.infer; + +interface CreateFilePreviewResponse { + baseUrl: string; + expiresAtMs: number; +} +type HostFileReadResponse = HostDaemonOnlineRpcResultByType["host.read_file"]; +type HostFileWriteResponse = HostDaemonOnlineRpcResultByType["host.write_file"]; +type HostFileListResponse = HostDaemonOnlineRpcResultByType["host.list_files"]; +type HostPathListResponse = HostDaemonOnlineRpcResultByType["host.list_paths"]; +type HostMkdirResponse = HostDaemonOnlineRpcResultByType["host.mkdir"]; +type HostMovePathResponse = HostDaemonOnlineRpcResultByType["host.move_path"]; +type HostRemovePathResponse = HostDaemonOnlineRpcResultByType["host.remove_path"]; + +/** + * Query for `GET /hosts/:id/directory`, the interactive path browser's + * single-level directory read. `path` is an absolute directory on the host; + * omitting it lists the host's home directory (the daemon resolves it, since a + * remote caller cannot know the host's home). + */ +declare const hostDirectoryQuerySchema: z$1.ZodObject<{ + path: z$1.ZodOptional; +}, z$1.core.$strip>; +type HostDirectoryQuery = z$1.infer; +declare const hostDirectoryListingSchema: z$1.ZodObject<{ + directory: z$1.ZodString; + parent: z$1.ZodNullable; + entries: z$1.ZodArray; + name: z$1.ZodString; + path: z$1.ZodString; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type HostDirectoryListing = z$1.infer; +/** Project name is sent so the daemon can derive its host-local checkout path. */ +declare const hostCloneDefaultPathQuerySchema: z$1.ZodObject<{ + projectId: z$1.ZodString; +}, z$1.core.$strip>; +type HostCloneDefaultPathQuery = z$1.infer; +declare const hostCloneDefaultPathResponseSchema: z$1.ZodObject<{ + path: z$1.ZodString; +}, z$1.core.$strict>; +type HostCloneDefaultPathResponse = z$1.infer; +declare const createHostJoinCodeResponseSchema: z$1.ZodObject<{ + joinCode: z$1.ZodString; + hostId: z$1.ZodString; + expiresAt: z$1.ZodNumber; +}, z$1.core.$strip>; +type CreateHostJoinCodeResponse = z$1.infer; +declare const updateHostRequestSchema: z$1.ZodObject<{ + name: z$1.ZodString; +}, z$1.core.$strict>; +type UpdateHostRequest = z$1.infer; +declare const hostRetryUpdateResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; +}, z$1.core.$strict>; +type HostRetryUpdateResponse = z$1.infer; +type HostPathsExistRequest = PathsExistRequest; +type HostPathsExistResponse = PathsExistResponse; +declare const hostPickFolderRequestSchema: z$1.ZodObject<{ + clientHostId: z$1.ZodString; +}, z$1.core.$strict>; +type HostPickFolderRequest = z$1.infer; +type HostPickFolderResponse = PickFolderResponse; +type HostProviderCliStatusResponse = ProviderCliStatusResponse; +type HostProviderCliInstallRequest = ProviderCliInstallRequest; +type HostProviderCliInstallEvent = ProviderCliInstallEvent; + +declare const pluginUpdateCheckEntrySchema: z$1.ZodObject<{ + id: z$1.ZodString; + outcome: z$1.ZodEnum<{ + unavailable: "unavailable"; + incompatible: "incompatible"; + current: "current"; + "update-available": "update-available"; + pinned: "pinned"; + }>; + devMode: z$1.ZodOptional>; + installed: z$1.ZodObject<{ + version: z$1.ZodString; + display: z$1.ZodString; + }, z$1.core.$strip>; + candidate: z$1.ZodOptional>; + blocked: z$1.ZodOptional; + }, z$1.core.$strip>>; + detail: z$1.ZodOptional; +}, z$1.core.$strip>; +type PluginUpdateCheckEntry = z$1.infer; +declare const pluginApplyUpdateResultSchema: z$1.ZodObject<{ + applied: z$1.ZodBoolean; + from: z$1.ZodObject<{ + version: z$1.ZodString; + display: z$1.ZodString; + }, z$1.core.$strip>; + to: z$1.ZodOptional>; + outcome: z$1.ZodEnum<{ + current: "current"; + updated: "updated"; + "rolled-back": "rolled-back"; + }>; + detail: z$1.ZodOptional; +}, z$1.core.$strip>; +type PluginApplyUpdateResult$1 = z$1.infer; +declare const pluginSourceDetailSchema: z$1.ZodObject<{ + requested: z$1.ZodString; + resolved: z$1.ZodString; + integrity: z$1.ZodOptional; + registry: z$1.ZodOptional; + engines: z$1.ZodObject<{ + bb: z$1.ZodOptional; + bbPluginSdk: z$1.ZodOptional; + }, z$1.core.$strip>; + installedAt: z$1.ZodOptional; + history: z$1.ZodArray>; +}, z$1.core.$strip>; +type PluginSourceDetail = z$1.infer; +declare const installedPluginSchema: z$1.ZodObject<{ + id: z$1.ZodString; + source: z$1.ZodString; + rootDir: z$1.ZodString; + version: z$1.ZodString; + provenance: z$1.ZodEnum<{ + builtin: "builtin"; + direct: "direct"; + catalog: "catalog"; + }>; + isOrphanedBuiltin: z$1.ZodBoolean; + catalogEntryId: z$1.ZodOptional; + sourceDisplay: z$1.ZodString; + updateState: z$1.ZodObject<{ + outcome: z$1.ZodOptional>; + availableVersion: z$1.ZodOptional; + blockedVersion: z$1.ZodOptional; + blockedReasons: z$1.ZodOptional>; + lastCheckAt: z$1.ZodOptional; + lastFailure: z$1.ZodOptional>; + }, z$1.core.$strip>; + enabled: z$1.ZodBoolean; + description: z$1.ZodNullable; + name: z$1.ZodNullable; + icon: z$1.ZodNullable; + status: z$1.ZodEnum<{ + error: "error"; + running: "running"; + missing: "missing"; + incompatible: "incompatible"; + disabled: "disabled"; + degraded: "degraded"; + "needs-configuration": "needs-configuration"; + }>; + statusDetail: z$1.ZodNullable; + handlerStats: z$1.ZodObject<{ + count: z$1.ZodNumber; + totalMs: z$1.ZodNumber; + maxMs: z$1.ZodNumber; + errorCount: z$1.ZodNumber; + }, z$1.core.$strip>; + services: z$1.ZodArray; + }, z$1.core.$strip>>; + schedules: z$1.ZodArray; + lastStatus: z$1.ZodNullable>; + lastError: z$1.ZodNullable; + }, z$1.core.$strip>>; + cliCommand: z$1.ZodNullable>; + hasSettings: z$1.ZodBoolean; + app: z$1.ZodObject<{ + hasApp: z$1.ZodBoolean; + bundle: z$1.ZodNullable; + hash: z$1.ZodString; + sdkMajor: z$1.ZodNumber; + sdkVersion: z$1.ZodString; + compatible: z$1.ZodBoolean; + }, z$1.core.$strip>>; + }, z$1.core.$strip>; + logoUrl: z$1.ZodNullable; + logoDarkUrl: z$1.ZodNullable; +}, z$1.core.$strip>; +type InstalledPlugin = z$1.infer; +declare const pluginListResponseSchema: z$1.ZodObject<{ + enabled: z$1.ZodBoolean; + plugins: z$1.ZodArray; + isOrphanedBuiltin: z$1.ZodBoolean; + catalogEntryId: z$1.ZodOptional; + sourceDisplay: z$1.ZodString; + updateState: z$1.ZodObject<{ + outcome: z$1.ZodOptional>; + availableVersion: z$1.ZodOptional; + blockedVersion: z$1.ZodOptional; + blockedReasons: z$1.ZodOptional>; + lastCheckAt: z$1.ZodOptional; + lastFailure: z$1.ZodOptional>; + }, z$1.core.$strip>; + enabled: z$1.ZodBoolean; + description: z$1.ZodNullable; + name: z$1.ZodNullable; + icon: z$1.ZodNullable; + status: z$1.ZodEnum<{ + error: "error"; + running: "running"; + missing: "missing"; + incompatible: "incompatible"; + disabled: "disabled"; + degraded: "degraded"; + "needs-configuration": "needs-configuration"; + }>; + statusDetail: z$1.ZodNullable; + handlerStats: z$1.ZodObject<{ + count: z$1.ZodNumber; + totalMs: z$1.ZodNumber; + maxMs: z$1.ZodNumber; + errorCount: z$1.ZodNumber; + }, z$1.core.$strip>; + services: z$1.ZodArray; + }, z$1.core.$strip>>; + schedules: z$1.ZodArray; + lastStatus: z$1.ZodNullable>; + lastError: z$1.ZodNullable; + }, z$1.core.$strip>>; + cliCommand: z$1.ZodNullable>; + hasSettings: z$1.ZodBoolean; + app: z$1.ZodObject<{ + hasApp: z$1.ZodBoolean; + bundle: z$1.ZodNullable; + hash: z$1.ZodString; + sdkMajor: z$1.ZodNumber; + sdkVersion: z$1.ZodString; + compatible: z$1.ZodBoolean; + }, z$1.core.$strip>>; + }, z$1.core.$strip>; + logoUrl: z$1.ZodNullable; + logoDarkUrl: z$1.ZodNullable; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type PluginListResponse = z$1.infer; +declare const pluginReloadResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; + plugins: z$1.ZodArray; + isOrphanedBuiltin: z$1.ZodBoolean; + catalogEntryId: z$1.ZodOptional; + sourceDisplay: z$1.ZodString; + updateState: z$1.ZodObject<{ + outcome: z$1.ZodOptional>; + availableVersion: z$1.ZodOptional; + blockedVersion: z$1.ZodOptional; + blockedReasons: z$1.ZodOptional>; + lastCheckAt: z$1.ZodOptional; + lastFailure: z$1.ZodOptional>; + }, z$1.core.$strip>; + enabled: z$1.ZodBoolean; + description: z$1.ZodNullable; + name: z$1.ZodNullable; + icon: z$1.ZodNullable; + status: z$1.ZodEnum<{ + error: "error"; + running: "running"; + missing: "missing"; + incompatible: "incompatible"; + disabled: "disabled"; + degraded: "degraded"; + "needs-configuration": "needs-configuration"; + }>; + statusDetail: z$1.ZodNullable; + handlerStats: z$1.ZodObject<{ + count: z$1.ZodNumber; + totalMs: z$1.ZodNumber; + maxMs: z$1.ZodNumber; + errorCount: z$1.ZodNumber; + }, z$1.core.$strip>; + services: z$1.ZodArray; + }, z$1.core.$strip>>; + schedules: z$1.ZodArray; + lastStatus: z$1.ZodNullable>; + lastError: z$1.ZodNullable; + }, z$1.core.$strip>>; + cliCommand: z$1.ZodNullable>; + hasSettings: z$1.ZodBoolean; + app: z$1.ZodObject<{ + hasApp: z$1.ZodBoolean; + bundle: z$1.ZodNullable; + hash: z$1.ZodString; + sdkMajor: z$1.ZodNumber; + sdkVersion: z$1.ZodString; + compatible: z$1.ZodBoolean; + }, z$1.core.$strip>>; + }, z$1.core.$strip>; + logoUrl: z$1.ZodNullable; + logoDarkUrl: z$1.ZodNullable; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type PluginReloadResponse = z$1.infer; +declare const pluginRemoveResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; +}, z$1.core.$strip>; +type PluginRemoveResponse = z$1.infer; +declare const pluginSettingsResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; + schema: z$1.ZodRecord; + secret: z$1.ZodOptional>; + default: z$1.ZodOptional; + label: z$1.ZodString; + description: z$1.ZodOptional; + }, z$1.core.$strict>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"boolean">; + default: z$1.ZodOptional; + label: z$1.ZodString; + description: z$1.ZodOptional; + }, z$1.core.$strict>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"select">; + options: z$1.ZodArray; + default: z$1.ZodOptional; + label: z$1.ZodString; + description: z$1.ZodOptional; + }, z$1.core.$strict>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"project">; + default: z$1.ZodOptional; + label: z$1.ZodString; + description: z$1.ZodOptional; + }, z$1.core.$strict>], "type">>; + values: z$1.ZodRecord>>; +}, z$1.core.$strip>; +type PluginSettingsResponse = z$1.infer; +declare const pluginTokenResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; + token: z$1.ZodString; +}, z$1.core.$strip>; +type PluginTokenResponse = z$1.infer; +declare const pluginCatalogStatusSchema: z$1.ZodObject<{ + pluginCount: z$1.ZodNumber; +}, z$1.core.$strip>; +type PluginCatalogStatus = z$1.infer; +declare const pluginCatalogSearchResultSchema: z$1.ZodObject<{ + entryId: z$1.ZodString; + displayName: z$1.ZodString; + description: z$1.ZodString; + icon: z$1.ZodNullable; + category: z$1.ZodString; + source: z$1.ZodString; + installed: z$1.ZodBoolean; + compatible: z$1.ZodBoolean; + incompatibleReason: z$1.ZodNullable; +}, z$1.core.$strip>; +type PluginCatalogSearchResult$1 = z$1.infer; + +declare const systemExecutionOptionsResponseSchema: z$1.ZodObject<{ + providers: z$1.ZodArray; + capabilities: z$1.ZodObject<{ + supportsArchive: z$1.ZodBoolean; + supportsRename: z$1.ZodBoolean; + supportsServiceTier: z$1.ZodBoolean; + supportsUserQuestion: z$1.ZodBoolean; + supportsFork: z$1.ZodBoolean; + supportedPermissionModes: z$1.ZodArray>; + }, z$1.core.$strip>; + composerActions: z$1.ZodArray; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plan">; + command: z$1.ZodObject<{ + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + trailingText: z$1.ZodString; + }, z$1.core.$strip>; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"goal">; + command: z$1.ZodObject<{ + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + trailingText: z$1.ZodString; + }, z$1.core.$strip>; + }, z$1.core.$strip>], "kind">>; + available: z$1.ZodBoolean; + }, z$1.core.$strip>>; + models: z$1.ZodArray; + description: z$1.ZodString; + }, z$1.core.$strip>>; + defaultReasoningEffort: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + isDefault: z$1.ZodBoolean; + }, z$1.core.$strip>>; + selectedOnlyModels: z$1.ZodArray; + description: z$1.ZodString; + }, z$1.core.$strip>>; + defaultReasoningEffort: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + isDefault: z$1.ZodBoolean; + }, z$1.core.$strip>>; + modelLoadError: z$1.ZodNullable; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type SystemExecutionOptionsResponse = z$1.infer; +declare const systemExecutionOptionsQuerySchema: z$1.ZodObject<{ + providerId: z$1.ZodOptional; + hostId: z$1.ZodOptional; + environmentId: z$1.ZodOptional; +}, z$1.core.$strip>; +type SystemExecutionOptionsQuery = z$1.infer; +/** Omission preserves the existing behavior of reading the primary machine. */ +declare const systemUsageLimitsQuerySchema: z$1.ZodObject<{ + hostId: z$1.ZodOptional; +}, z$1.core.$strip>; +type SystemUsageLimitsQuery = z$1.infer; +declare const systemVoiceTranscriptionResponseSchema: z$1.ZodObject<{ + text: z$1.ZodString; +}, z$1.core.$strip>; +type SystemVoiceTranscriptionResponse = z$1.infer; +declare const systemConfigResponseSchema: z$1.ZodObject<{ + generalSettings: z$1.ZodObject<{ + caffeinate: z$1.ZodBoolean; + showKeyboardHints: z$1.ZodBoolean; + showUnhandledProviderEvents: z$1.ZodBoolean; + codexMemoryEnabled: z$1.ZodBoolean; + claudeCodeMemoryEnabled: z$1.ZodBoolean; + codexSubagentsDisabled: z$1.ZodBoolean; + claudeCodeSubagentsDisabled: z$1.ZodBoolean; + claudeCodeWorkflowsDisabled: z$1.ZodBoolean; + }, z$1.core.$strict>; + keybindings: z$1.ZodArray; + desktopOnly: z$1.ZodBoolean; + shortcut: z$1.ZodObject<{ + key: z$1.ZodString; + mod: z$1.ZodBoolean; + meta: z$1.ZodBoolean; + control: z$1.ZodBoolean; + alt: z$1.ZodBoolean; + shift: z$1.ZodBoolean; + }, z$1.core.$strict>; + when: z$1.ZodObject<{ + all: z$1.ZodArray>; + none: z$1.ZodArray>; + }, z$1.core.$strict>; + }, z$1.core.$strict>>; + defaultKeybindings: z$1.ZodArray; + desktopOnly: z$1.ZodBoolean; + shortcut: z$1.ZodObject<{ + key: z$1.ZodString; + mod: z$1.ZodBoolean; + meta: z$1.ZodBoolean; + control: z$1.ZodBoolean; + alt: z$1.ZodBoolean; + shift: z$1.ZodBoolean; + }, z$1.core.$strict>; + when: z$1.ZodObject<{ + all: z$1.ZodArray>; + none: z$1.ZodArray>; + }, z$1.core.$strict>; + }, z$1.core.$strict>>; + keybindingOverrides: z$1.ZodArray; + shortcut: z$1.ZodNullable>; + }, z$1.core.$strict>>; + experiments: z$1.ZodObject<{ + claudeCodeMockCliTraffic: z$1.ZodBoolean; + plugins: z$1.ZodBoolean; + sideChatPlugin: z$1.ZodBoolean; + }, z$1.core.$strip>; + appearance: z$1.ZodObject<{ + themeId: z$1.ZodString; + customCss: z$1.ZodNullable; + faviconColor: z$1.ZodEnum<{ + default: "default"; + red: "red"; + orange: "orange"; + yellow: "yellow"; + green: "green"; + teal: "teal"; + blue: "blue"; + purple: "purple"; + pink: "pink"; + }>; + }, z$1.core.$strip>; + customThemes: z$1.ZodArray; + pluginThemes: z$1.ZodArray; + }, z$1.core.$strip>>; + featureFlags: z$1.ZodObject<{ + placeholder: z$1.ZodBoolean; + }, z$1.core.$strip>; + hostDaemonPort: z$1.ZodNullable; + primaryHostId: z$1.ZodNullable; + primaryHostPlatform: z$1.ZodNullable>; + voiceTranscriptionEnabled: z$1.ZodBoolean; + dataDir: z$1.ZodString; +}, z$1.core.$strip>; +type SystemConfigResponse = z$1.infer; +declare const systemAttentionResponseSchema: z$1.ZodObject<{ + hasAttention: z$1.ZodBoolean; +}, z$1.core.$strip>; +type SystemAttentionResponse = z$1.infer; +/** + * Theme catalog: the on-disk custom-theme directory plus the discovered custom + * themes and the active palette. Drives `bb theme list` / `bb theme dir`. + */ +declare const themeCatalogResponseSchema: z$1.ZodObject<{ + dir: z$1.ZodString; + custom: z$1.ZodArray; + plugins: z$1.ZodArray; + }, z$1.core.$strip>>; + active: z$1.ZodObject<{ + themeId: z$1.ZodString; + customCss: z$1.ZodNullable; + faviconColor: z$1.ZodEnum<{ + default: "default"; + red: "red"; + orange: "orange"; + yellow: "yellow"; + green: "green"; + teal: "teal"; + blue: "blue"; + purple: "purple"; + pink: "pink"; + }>; + }, z$1.core.$strip>; +}, z$1.core.$strip>; +type ThemeCatalogResponse = z$1.infer; +declare const systemVersionResponseSchema: z$1.ZodObject<{ + currentVersion: z$1.ZodString; + latestVersion: z$1.ZodNullable; + source: z$1.ZodLiteral<"npm">; + updateAvailable: z$1.ZodBoolean; + isDevelopment: z$1.ZodBoolean; + upgradeCommand: z$1.ZodString; +}, z$1.core.$strip>; +type SystemVersionResponse = z$1.infer; +declare const systemConfigReloadResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; +}, z$1.core.$strip>; +type SystemConfigReloadResponse = z$1.infer; + +declare const terminalSessionSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodNullable; + environmentId: z$1.ZodNullable; + hostId: z$1.ZodString; + title: z$1.ZodString; + initialCwd: z$1.ZodString; + cols: z$1.ZodNumber; + rows: z$1.ZodNumber; + status: z$1.ZodEnum<{ + starting: "starting"; + disconnected: "disconnected"; + running: "running"; + exited: "exited"; + }>; + exitCode: z$1.ZodNullable; + closeReason: z$1.ZodNullable>; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + lastUserInputAt: z$1.ZodNullable; +}, z$1.core.$strip>; +type TerminalSession = z$1.infer; +declare const terminalListResponseSchema: z$1.ZodObject<{ + sessions: z$1.ZodArray; + environmentId: z$1.ZodNullable; + hostId: z$1.ZodString; + title: z$1.ZodString; + initialCwd: z$1.ZodString; + cols: z$1.ZodNumber; + rows: z$1.ZodNumber; + status: z$1.ZodEnum<{ + starting: "starting"; + disconnected: "disconnected"; + running: "running"; + exited: "exited"; + }>; + exitCode: z$1.ZodNullable; + closeReason: z$1.ZodNullable>; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + lastUserInputAt: z$1.ZodNullable; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type TerminalListResponse = z$1.infer; +declare const createTerminalRequestSchema: z$1.ZodObject<{ + cols: z$1.ZodNumber; + rows: z$1.ZodNumber; + start: z$1.ZodOptional; + }, z$1.core.$strict>, z$1.ZodObject<{ + mode: z$1.ZodLiteral<"command">; + command: z$1.ZodString; + }, z$1.core.$strict>], "mode">>; + target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"environment">; + environmentId: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"host_path">; + hostId: z$1.ZodString; + cwd: z$1.ZodNullable; + }, z$1.core.$strict>], "kind">; + title: z$1.ZodOptional; +}, z$1.core.$strict>; +type CreateTerminalRequest = z$1.infer; +declare const updateTerminalRequestSchema: z$1.ZodObject<{ + title: z$1.ZodString; +}, z$1.core.$strict>; +type UpdateTerminalRequest = z$1.infer; +declare const terminalInputRequestSchema: z$1.ZodObject<{ + dataBase64: z$1.ZodString; +}, z$1.core.$strict>; +type TerminalInputRequest = z$1.infer; +declare const terminalResizeRequestSchema: z$1.ZodObject<{ + cols: z$1.ZodNumber; + rows: z$1.ZodNumber; +}, z$1.core.$strict>; +type TerminalResizeRequest = z$1.infer; +declare const terminalOutputQuerySchema: z$1.ZodObject<{ + sinceSeq: z$1.ZodOptional>; + tailBytes: z$1.ZodOptional>; + limitChunks: z$1.ZodOptional>; +}, z$1.core.$strict>; +type TerminalOutputQuery = z$1.infer; +declare const terminalOutputResponseSchema: z$1.ZodObject<{ + chunks: z$1.ZodArray>; + nextSeq: z$1.ZodNumber; + truncated: z$1.ZodBoolean; +}, z$1.core.$strict>; +type TerminalOutputResponse = z$1.infer; + +declare const timelineRowStatusSchema: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; +}>; +type TimelineRowStatus = z$1.infer; +declare const timelineRowBaseSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; +}, z$1.core.$strip>; +type TimelineRowBase = z$1.infer; +declare const timelineConversationRowSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"conversation">; + text: z$1.ZodString; + attachments: z$1.ZodNullable; + localImagePaths: z$1.ZodArray; + localFilePaths: z$1.ZodArray; + }, z$1.core.$strip>>; + role: z$1.ZodLiteral<"user">; + initiator: z$1.ZodEnum<{ + user: "user"; + agent: "agent"; + system: "system"; + }>; + senderThreadId: z$1.ZodNullable; + systemMessageKind: z$1.ZodEnum<{ + "ownership-assigned": "ownership-assigned"; + "ownership-removed": "ownership-removed"; + "child-needs-attention": "child-needs-attention"; + "child-completed": "child-completed"; + "child-failed": "child-failed"; + "child-interrupted": "child-interrupted"; + "child-outcome-batch": "child-outcome-batch"; + unlabeled: "unlabeled"; + }>; + systemMessageSubject: z$1.ZodNullable; + threadId: z$1.ZodString; + threadName: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread-batch">; + count: z$1.ZodNumber; + }, z$1.core.$strip>], "kind">>; + turnRequest: z$1.ZodObject<{ + kind: z$1.ZodEnum<{ + message: "message"; + steer: "steer"; + }>; + status: z$1.ZodEnum<{ + pending: "pending"; + accepted: "accepted"; + }>; + }, z$1.core.$strip>; + mentions: z$1.ZodArray, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>; +}, z$1.core.$strip>, z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"conversation">; + text: z$1.ZodString; + attachments: z$1.ZodNullable; + localImagePaths: z$1.ZodArray; + localFilePaths: z$1.ZodArray; + }, z$1.core.$strip>>; + role: z$1.ZodLiteral<"assistant">; + turnRequest: z$1.ZodNull; +}, z$1.core.$strip>], "role">; +type TimelineConversationRow = z$1.infer; +declare const timelineSystemRowSchema: z$1.ZodUnion; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"system">; + title: z$1.ZodString; + detail: z$1.ZodNullable; + status: z$1.ZodNullable>; + systemKind: z$1.ZodEnum<{ + error: "error"; + debug: "debug"; + reconnect: "reconnect"; + }>; +}, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"system">; + title: z$1.ZodString; + detail: z$1.ZodNullable; + status: z$1.ZodNullable>; + systemKind: z$1.ZodLiteral<"operation">; + operationKind: z$1.ZodEnum<{ + generic: "generic"; + compaction: "compaction"; + "thread-provisioning": "thread-provisioning"; + "thread-interrupted": "thread-interrupted"; + "provider-unhandled": "provider-unhandled"; + warning: "warning"; + deprecation: "deprecation"; + }>; + completedAt: z$1.ZodNullable; +}, z$1.core.$strip>, z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"system">; + title: z$1.ZodString; + detail: z$1.ZodNullable; + systemKind: z$1.ZodLiteral<"operation">; + operationKind: z$1.ZodLiteral<"parent-change">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + parentChange: z$1.ZodObject<{ + action: z$1.ZodEnum<{ + assign: "assign"; + release: "release"; + transfer: "transfer"; + }>; + previousParentThreadId: z$1.ZodNullable; + previousParentThreadTitle: z$1.ZodNullable; + nextParentThreadId: z$1.ZodNullable; + nextParentThreadTitle: z$1.ZodNullable; + }, z$1.core.$strip>; + completedAt: z$1.ZodNullable; +}, z$1.core.$strip>], "operationKind">]>; +type TimelineSystemRow = z$1.infer; +interface TimelineWorkRowBase extends TimelineRowBase { + kind: "work"; + status: TimelineRowStatus; +} +declare const timelineCommandWorkRowSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"command">; + callId: z$1.ZodString; + command: z$1.ZodString; + cwd: z$1.ZodNullable; + source: z$1.ZodNullable; + output: z$1.ZodString; + exitCode: z$1.ZodNullable; + completedAt: z$1.ZodNullable; + approvalStatus: z$1.ZodNullable>; + activityIntents: z$1.ZodArray; + command: z$1.ZodString; + name: z$1.ZodString; + path: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"list_files">; + command: z$1.ZodString; + path: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"search">; + command: z$1.ZodString; + query: z$1.ZodNullable; + path: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"unknown">; + command: z$1.ZodString; + }, z$1.core.$strip>], "type">>; +}, z$1.core.$strip>; +type TimelineCommandWorkRow = z$1.infer; +declare const timelineToolWorkRowSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"tool">; + callId: z$1.ZodString; + toolName: z$1.ZodString; + toolArgs: z$1.ZodNullable>>>; + output: z$1.ZodString; + completedAt: z$1.ZodNullable; + approvalStatus: z$1.ZodNullable>; + activityIntents: z$1.ZodArray; + command: z$1.ZodString; + name: z$1.ZodString; + path: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"list_files">; + command: z$1.ZodString; + path: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"search">; + command: z$1.ZodString; + query: z$1.ZodNullable; + path: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"unknown">; + command: z$1.ZodString; + }, z$1.core.$strip>], "type">>; +}, z$1.core.$strip>; +type TimelineToolWorkRow = z$1.infer; +declare const timelineFileChangeWorkRowSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"file-change">; + callId: z$1.ZodString; + change: z$1.ZodObject<{ + path: z$1.ZodString; + kind: z$1.ZodNullable; + movePath: z$1.ZodNullable; + diff: z$1.ZodNullable; + diffStats: z$1.ZodObject<{ + added: z$1.ZodNumber; + removed: z$1.ZodNumber; + }, z$1.core.$strip>; + }, z$1.core.$strip>; + stdout: z$1.ZodNullable; + stderr: z$1.ZodNullable; + approvalStatus: z$1.ZodNullable>; +}, z$1.core.$strip>; +type TimelineFileChangeWorkRow = z$1.infer; +declare const timelineWebSearchWorkRowSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"web-search">; + callId: z$1.ZodString; + queries: z$1.ZodArray; + completedAt: z$1.ZodNullable; +}, z$1.core.$strip>; +type TimelineWebSearchWorkRow = z$1.infer; +declare const timelineWebFetchWorkRowSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"web-fetch">; + callId: z$1.ZodString; + url: z$1.ZodString; + prompt: z$1.ZodNullable; + pattern: z$1.ZodNullable; + completedAt: z$1.ZodNullable; +}, z$1.core.$strip>; +type TimelineWebFetchWorkRow = z$1.infer; +declare const timelineImageViewWorkRowSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"image-view">; + callId: z$1.ZodString; + path: z$1.ZodString; + completedAt: z$1.ZodNullable; +}, z$1.core.$strip>; +type TimelineImageViewWorkRow = z$1.infer; +declare const timelineApprovalWorkRowSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"approval">; + interactionId: z$1.ZodString; + target: z$1.ZodObject<{ + itemId: z$1.ZodString; + toolName: z$1.ZodNullable; + }, z$1.core.$strip>; + approvalKind: z$1.ZodLiteral<"file-edit">; + lifecycle: z$1.ZodEnum<{ + denied: "denied"; + waiting: "waiting"; + }>; +}, z$1.core.$strip>, z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"approval">; + interactionId: z$1.ZodString; + target: z$1.ZodObject<{ + itemId: z$1.ZodString; + toolName: z$1.ZodNullable; + }, z$1.core.$strip>; + approvalKind: z$1.ZodLiteral<"permission-grant">; + lifecycle: z$1.ZodEnum<{ + pending: "pending"; + interrupted: "interrupted"; + denied: "denied"; + resolving: "resolving"; + granted: "granted"; + }>; + grantScope: z$1.ZodNullable>; + statusReason: z$1.ZodNullable; +}, z$1.core.$strip>], "approvalKind">; +type TimelineApprovalWorkRow = z$1.infer; +declare const timelineQuestionWorkRowSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"question">; + interactionId: z$1.ZodString; + lifecycle: z$1.ZodEnum<{ + pending: "pending"; + interrupted: "interrupted"; + resolving: "resolving"; + answered: "answered"; + }>; + questions: z$1.ZodArray; + multiSelect: z$1.ZodBoolean; + options: z$1.ZodOptional; + }, z$1.core.$strip>>>; + allowFreeText: z$1.ZodBoolean; + }, z$1.core.$strip>>; + answers: z$1.ZodNullable; + freeText: z$1.ZodOptional; + }, z$1.core.$strip>>>; + statusReason: z$1.ZodNullable; +}, z$1.core.$strip>; +type TimelineQuestionWorkRow = z$1.infer; +interface TimelineDelegationWorkRow extends TimelineWorkRowBase { + workKind: "delegation"; + callId: string; + toolName: string; + subagentType: string | null; + description: string | null; + output: string; + completedAt: number | null; + childRows: TimelineRow[]; +} +/** + * A provider background task — a dynamic workflow (Claude Code Workflow tool) + * or a backgrounded shell command (Bash run_in_background), discriminated by + * `taskType`. The row outlives its spawning turn: progress and terminal state + * arrive via thread-scoped events folded into this single row. `workflow` is + * the merged phase/agent tree, present only for workflows; null for shell + * commands and for workflows the provider reported no progress records for + * (degraded rendering falls back to description + summary). + */ +declare const timelineWorkflowWorkRowSchema: z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + turnId: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"workflow">; + itemId: z$1.ZodString; + taskType: z$1.ZodString; + workflowName: z$1.ZodNullable; + description: z$1.ZodString; + taskStatus: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + running: "running"; + paused: "paused"; + failed: "failed"; + killed: "killed"; + stopped: "stopped"; + }>; + workflow: z$1.ZodNullable; + }, z$1.core.$strip>>; + agents: z$1.ZodArray; + model: z$1.ZodString; + attempt: z$1.ZodNumber; + cached: z$1.ZodBoolean; + lastProgressAt: z$1.ZodNumber; + phaseIndex: z$1.ZodOptional; + phaseTitle: z$1.ZodOptional; + agentType: z$1.ZodOptional; + isolation: z$1.ZodOptional; + queuedAt: z$1.ZodOptional; + startedAt: z$1.ZodOptional; + lastToolName: z$1.ZodOptional; + lastToolSummary: z$1.ZodOptional; + promptPreview: z$1.ZodOptional; + resultPreview: z$1.ZodOptional; + error: z$1.ZodOptional; + tokens: z$1.ZodOptional; + toolCalls: z$1.ZodOptional; + durationMs: z$1.ZodOptional; + }, z$1.core.$strip>>; + }, z$1.core.$strip>>; + usage: z$1.ZodNullable>; + summary: z$1.ZodNullable; + error: z$1.ZodNullable; + completedAt: z$1.ZodNullable; +}, z$1.core.$strip>; +type TimelineWorkflowWorkRow = z$1.infer; +type TimelineWorkRow = TimelineCommandWorkRow | TimelineToolWorkRow | TimelineFileChangeWorkRow | TimelineWebSearchWorkRow | TimelineWebFetchWorkRow | TimelineImageViewWorkRow | TimelineApprovalWorkRow | TimelineQuestionWorkRow | TimelineDelegationWorkRow | TimelineWorkflowWorkRow; +interface TimelineTurnRow extends TimelineRowBase { + kind: "turn"; + turnId: string; + status: TimelineRowStatus; + summaryCount: number; + completedAt: number | null; + children: TimelineRow[] | null; +} +type TimelineSourceRow = TimelineConversationRow | TimelineWorkRow | TimelineSystemRow; +type TimelineRow = TimelineSourceRow | TimelineTurnRow; + +declare const createThreadRequestSchema: z$1.ZodObject<{ + projectId: z$1.ZodString; + providerId: z$1.ZodOptional; + origin: z$1.ZodEnum<{ + plugin: "plugin"; + app: "app"; + cli: "cli"; + sdk: "sdk"; + }>; + originPluginId: z$1.ZodOptional; + visibility: z$1.ZodOptional>; + title: z$1.ZodOptional; + input: z$1.ZodArray>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>; + model: z$1.ZodOptional; + serviceTier: z$1.ZodOptional>; + reasoningLevel: z$1.ZodOptional>; + permissionMode: z$1.ZodOptional, z$1.ZodLiteral<"workspace-write">]>, z$1.ZodTransform<"accept-edits" | "auto" | "full", "accept-edits" | "auto" | "full" | "workspace-write">>>; + executionInputSources: z$1.ZodOptional>; + model: z$1.ZodOptional>; + serviceTier: z$1.ZodOptional>; + reasoningLevel: z$1.ZodOptional>; + permissionMode: z$1.ZodOptional>; + }, z$1.core.$strict>>; + environment: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + type: z$1.ZodLiteral<"reuse">; + environmentId: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"host">; + hostId: z$1.ZodOptional; + workspace: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + type: z$1.ZodLiteral<"unmanaged">; + path: z$1.ZodNullable; + branch: z$1.ZodOptional; + name: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"new">; + baseBranch: z$1.ZodString; + }, z$1.core.$strict>], "kind">>; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"managed-worktree">; + baseBranch: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"named">; + name: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"default">; + }, z$1.core.$strip>], "kind">; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"personal">; + }, z$1.core.$strip>], "type">; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"project-default">; + }, z$1.core.$strip>], "type">; + parentThreadId: z$1.ZodOptional; + sectionId: z$1.ZodOptional>; + sourceThreadId: z$1.ZodOptional; + sourceSeqEnd: z$1.ZodOptional; + startedOnBehalfOf: z$1.ZodDefault; + senderThreadId: z$1.ZodString; + }, z$1.core.$strip>>>; + originKind: z$1.ZodDefault>>; + childOrigin: z$1.ZodDefault>>; +}, z$1.core.$strip>; +type CreateThreadRequest = z$1.infer; +declare const forkThreadRequestSchema: z$1.ZodObject<{ + sourceThreadId: z$1.ZodString; + sourceSeqEnd: z$1.ZodOptional; + input: z$1.ZodOptional>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>>; + agentContextSeed: z$1.ZodOptional>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">, z$1.ZodObject<{ + visibility: z$1.ZodLiteral<"agent-only">; + }, z$1.core.$strip>>>>; + title: z$1.ZodOptional; + permissionMode: z$1.ZodOptional, z$1.ZodLiteral<"workspace-write">]>, z$1.ZodTransform<"accept-edits" | "auto" | "full", "accept-edits" | "auto" | "full" | "workspace-write">>>; + visibility: z$1.ZodDefault>; + workspace: z$1.ZodDefault>; + origin: z$1.ZodDefault>; + originPluginId: z$1.ZodOptional; +}, z$1.core.$strip>; +type ForkThreadRequest = z$1.infer; +declare const sendMessageRequestSchema: z$1.ZodObject<{ + input: z$1.ZodArray>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>; + model: z$1.ZodOptional; + serviceTier: z$1.ZodOptional>; + reasoningLevel: z$1.ZodOptional>; + permissionMode: z$1.ZodOptional, z$1.ZodLiteral<"workspace-write">]>, z$1.ZodTransform<"accept-edits" | "auto" | "full", "accept-edits" | "auto" | "full" | "workspace-write">>>; + executionInputSources: z$1.ZodOptional>; + serviceTier: z$1.ZodOptional>; + reasoningLevel: z$1.ZodOptional>; + permissionMode: z$1.ZodOptional>; + }, z$1.core.$strict>>; + mode: z$1.ZodEnum<{ + steer: "steer"; + start: "start"; + auto: "auto"; + "queue-if-active": "queue-if-active"; + "steer-if-active": "steer-if-active"; + }>; + senderThreadId: z$1.ZodOptional; +}, z$1.core.$strip>; +type SendMessageRequest = z$1.infer; +declare const createQueuedMessageRequestSchema: z$1.ZodObject<{ + input: z$1.ZodArray>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>; + model: z$1.ZodOptional; + serviceTier: z$1.ZodOptional>; + reasoningLevel: z$1.ZodOptional>; + permissionMode: z$1.ZodOptional, z$1.ZodLiteral<"workspace-write">]>, z$1.ZodTransform<"accept-edits" | "auto" | "full", "accept-edits" | "auto" | "full" | "workspace-write">>>; + executionInputSources: z$1.ZodOptional>; + serviceTier: z$1.ZodOptional>; + reasoningLevel: z$1.ZodOptional>; + permissionMode: z$1.ZodOptional>; + }, z$1.core.$strict>>; + senderThreadId: z$1.ZodOptional; +}, z$1.core.$strip>; +type CreateQueuedMessageRequest = z$1.infer; +declare const updateQueuedMessageRequestSchema: z$1.ZodObject<{ + expectedUpdatedAt: z$1.ZodNumber; + input: z$1.ZodArray>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>; +}, z$1.core.$strip>; +type UpdateQueuedMessageRequest = z$1.infer; +declare const sendQueuedMessageRequestSchema: z$1.ZodObject<{ + mode: z$1.ZodEnum<{ + steer: "steer"; + auto: "auto"; + }>; +}, z$1.core.$strip>; +type SendQueuedMessageRequest = z$1.infer; +declare const reorderQueuedMessageRequestSchema: z$1.ZodObject<{ + previousQueuedMessageId: z$1.ZodNullable; + nextQueuedMessageId: z$1.ZodNullable; + groupBoundaryQueuedMessageId: z$1.ZodOptional; +}, z$1.core.$strip>; +type ReorderQueuedMessageRequest = z$1.infer; +declare const setQueuedMessageGroupBoundaryRequestSchema: z$1.ZodObject<{ + expectedGroupedPrefixQueuedMessageIds: z$1.ZodArray; + groupBoundaryQueuedMessageId: z$1.ZodString; +}, z$1.core.$strip>; +type SetQueuedMessageGroupBoundaryRequest = z$1.infer; +declare const sendQueuedMessageResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; + queuedMessage: z$1.ZodObject<{ + id: z$1.ZodString; + content: z$1.ZodArray>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>; + model: z$1.ZodString; + reasoningLevel: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + permissionMode: z$1.ZodEnum<{ + "accept-edits": "accept-edits"; + auto: "auto"; + full: "full"; + }>; + serviceTier: z$1.ZodEnum<{ + default: "default"; + fast: "fast"; + }>; + groupWithNext: z$1.ZodBoolean; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + }, z$1.core.$strip>; +}, z$1.core.$strip>; +type SendQueuedMessageResponse = z$1.infer; +declare const threadListResponseSchema: z$1.ZodArray; + providerId: z$1.ZodString; + title: z$1.ZodNullable; + titleFallback: z$1.ZodNullable; + sectionId: z$1.ZodNullable; + status: z$1.ZodEnum<{ + error: "error"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + }>; + parentThreadId: z$1.ZodNullable; + sourceThreadId: z$1.ZodNullable; + originKind: z$1.ZodNullable>; + childOrigin: z$1.ZodNullable>; + originPluginId: z$1.ZodNullable; + visibility: z$1.ZodEnum<{ + visible: "visible"; + hidden: "hidden"; + }>; + archivedAt: z$1.ZodNullable; + pinnedAt: z$1.ZodNullable; + deletedAt: z$1.ZodNullable; + lastReadAt: z$1.ZodNullable; + latestAttentionAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + runtime: z$1.ZodObject<{ + displayStatus: z$1.ZodEnum<{ + error: "error"; + provisioning: "provisioning"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + "host-reconnecting": "host-reconnecting"; + "waiting-for-host": "waiting-for-host"; + }>; + hostReconnectGraceExpiresAt: z$1.ZodNullable; + }, z$1.core.$strip>; + activity: z$1.ZodObject<{ + activeWorkflowCount: z$1.ZodNumber; + activeBackgroundAgentCount: z$1.ZodNumber; + activeBackgroundCommandCount: z$1.ZodNumber; + activePlanModeCount: z$1.ZodNumber; + activeGoalCount: z$1.ZodNumber; + }, z$1.core.$strip>; + pinSortKey: z$1.ZodNullable; + hasPendingInteraction: z$1.ZodBoolean; + environmentHostId: z$1.ZodNullable; + environmentName: z$1.ZodNullable; + environmentBranchName: z$1.ZodNullable; + environmentWorkspaceDisplayKind: z$1.ZodEnum<{ + "managed-worktree": "managed-worktree"; + "unmanaged-worktree": "unmanaged-worktree"; + other: "other"; + }>; +}, z$1.core.$strip>>; +type ThreadListResponse = z$1.infer; +declare const threadSearchResponseSchema: z$1.ZodObject<{ + active: z$1.ZodObject<{ + total: z$1.ZodNumber; + results: z$1.ZodArray; + providerId: z$1.ZodString; + title: z$1.ZodNullable; + titleFallback: z$1.ZodNullable; + sectionId: z$1.ZodNullable; + status: z$1.ZodEnum<{ + error: "error"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + }>; + parentThreadId: z$1.ZodNullable; + sourceThreadId: z$1.ZodNullable; + originKind: z$1.ZodNullable>; + childOrigin: z$1.ZodNullable>; + originPluginId: z$1.ZodNullable; + visibility: z$1.ZodEnum<{ + visible: "visible"; + hidden: "hidden"; + }>; + archivedAt: z$1.ZodNullable; + pinnedAt: z$1.ZodNullable; + deletedAt: z$1.ZodNullable; + lastReadAt: z$1.ZodNullable; + latestAttentionAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + runtime: z$1.ZodObject<{ + displayStatus: z$1.ZodEnum<{ + error: "error"; + provisioning: "provisioning"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + "host-reconnecting": "host-reconnecting"; + "waiting-for-host": "waiting-for-host"; + }>; + hostReconnectGraceExpiresAt: z$1.ZodNullable; + }, z$1.core.$strip>; + activity: z$1.ZodObject<{ + activeWorkflowCount: z$1.ZodNumber; + activeBackgroundAgentCount: z$1.ZodNumber; + activeBackgroundCommandCount: z$1.ZodNumber; + activePlanModeCount: z$1.ZodNumber; + activeGoalCount: z$1.ZodNumber; + }, z$1.core.$strip>; + pinSortKey: z$1.ZodNullable; + hasPendingInteraction: z$1.ZodBoolean; + environmentHostId: z$1.ZodNullable; + environmentName: z$1.ZodNullable; + environmentBranchName: z$1.ZodNullable; + environmentWorkspaceDisplayKind: z$1.ZodEnum<{ + "managed-worktree": "managed-worktree"; + "unmanaged-worktree": "unmanaged-worktree"; + other: "other"; + }>; + }, z$1.core.$strip>; + matches: z$1.ZodArray; + text: z$1.ZodString; + highlightRanges: z$1.ZodArray>; + sourceSeq: z$1.ZodNullable; + }, z$1.core.$strict>>; + }, z$1.core.$strict>>; + }, z$1.core.$strict>; + archived: z$1.ZodObject<{ + total: z$1.ZodNumber; + results: z$1.ZodArray; + providerId: z$1.ZodString; + title: z$1.ZodNullable; + titleFallback: z$1.ZodNullable; + sectionId: z$1.ZodNullable; + status: z$1.ZodEnum<{ + error: "error"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + }>; + parentThreadId: z$1.ZodNullable; + sourceThreadId: z$1.ZodNullable; + originKind: z$1.ZodNullable>; + childOrigin: z$1.ZodNullable>; + originPluginId: z$1.ZodNullable; + visibility: z$1.ZodEnum<{ + visible: "visible"; + hidden: "hidden"; + }>; + archivedAt: z$1.ZodNullable; + pinnedAt: z$1.ZodNullable; + deletedAt: z$1.ZodNullable; + lastReadAt: z$1.ZodNullable; + latestAttentionAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + runtime: z$1.ZodObject<{ + displayStatus: z$1.ZodEnum<{ + error: "error"; + provisioning: "provisioning"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + "host-reconnecting": "host-reconnecting"; + "waiting-for-host": "waiting-for-host"; + }>; + hostReconnectGraceExpiresAt: z$1.ZodNullable; + }, z$1.core.$strip>; + activity: z$1.ZodObject<{ + activeWorkflowCount: z$1.ZodNumber; + activeBackgroundAgentCount: z$1.ZodNumber; + activeBackgroundCommandCount: z$1.ZodNumber; + activePlanModeCount: z$1.ZodNumber; + activeGoalCount: z$1.ZodNumber; + }, z$1.core.$strip>; + pinSortKey: z$1.ZodNullable; + hasPendingInteraction: z$1.ZodBoolean; + environmentHostId: z$1.ZodNullable; + environmentName: z$1.ZodNullable; + environmentBranchName: z$1.ZodNullable; + environmentWorkspaceDisplayKind: z$1.ZodEnum<{ + "managed-worktree": "managed-worktree"; + "unmanaged-worktree": "unmanaged-worktree"; + other: "other"; + }>; + }, z$1.core.$strip>; + matches: z$1.ZodArray; + text: z$1.ZodString; + highlightRanges: z$1.ZodArray>; + sourceSeq: z$1.ZodNullable; + }, z$1.core.$strict>>; + }, z$1.core.$strict>>; + }, z$1.core.$strict>; +}, z$1.core.$strict>; +type ThreadSearchResponse = z$1.infer; +declare const threadResponseSchema: z$1.ZodObject<{ + id: z$1.ZodString; + projectId: z$1.ZodString; + environmentId: z$1.ZodNullable; + providerId: z$1.ZodString; + title: z$1.ZodNullable; + titleFallback: z$1.ZodNullable; + sectionId: z$1.ZodNullable; + status: z$1.ZodEnum<{ + error: "error"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + }>; + parentThreadId: z$1.ZodNullable; + sourceThreadId: z$1.ZodNullable; + originKind: z$1.ZodNullable>; + childOrigin: z$1.ZodNullable>; + originPluginId: z$1.ZodNullable; + visibility: z$1.ZodEnum<{ + visible: "visible"; + hidden: "hidden"; + }>; + archivedAt: z$1.ZodNullable; + pinnedAt: z$1.ZodNullable; + deletedAt: z$1.ZodNullable; + lastReadAt: z$1.ZodNullable; + latestAttentionAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + runtime: z$1.ZodObject<{ + displayStatus: z$1.ZodEnum<{ + error: "error"; + provisioning: "provisioning"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + "host-reconnecting": "host-reconnecting"; + "waiting-for-host": "waiting-for-host"; + }>; + hostReconnectGraceExpiresAt: z$1.ZodNullable; + }, z$1.core.$strip>; + canSpawnChild: z$1.ZodBoolean; +}, z$1.core.$strip>; +type ThreadResponse = z$1.infer; +declare const threadGetQuerySchema: z$1.ZodObject<{ + include: z$1.ZodOptional; +}, z$1.core.$strip>; +type ThreadGetQuery = z$1.infer; +declare const threadWithIncludesResponseSchema: z$1.ZodObject<{ + id: z$1.ZodString; + projectId: z$1.ZodString; + environmentId: z$1.ZodNullable; + providerId: z$1.ZodString; + title: z$1.ZodNullable; + titleFallback: z$1.ZodNullable; + sectionId: z$1.ZodNullable; + status: z$1.ZodEnum<{ + error: "error"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + }>; + parentThreadId: z$1.ZodNullable; + sourceThreadId: z$1.ZodNullable; + originKind: z$1.ZodNullable>; + childOrigin: z$1.ZodNullable>; + originPluginId: z$1.ZodNullable; + visibility: z$1.ZodEnum<{ + visible: "visible"; + hidden: "hidden"; + }>; + archivedAt: z$1.ZodNullable; + pinnedAt: z$1.ZodNullable; + deletedAt: z$1.ZodNullable; + lastReadAt: z$1.ZodNullable; + latestAttentionAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + runtime: z$1.ZodObject<{ + displayStatus: z$1.ZodEnum<{ + error: "error"; + provisioning: "provisioning"; + stopping: "stopping"; + idle: "idle"; + starting: "starting"; + active: "active"; + "host-reconnecting": "host-reconnecting"; + "waiting-for-host": "waiting-for-host"; + }>; + hostReconnectGraceExpiresAt: z$1.ZodNullable; + }, z$1.core.$strip>; + canSpawnChild: z$1.ZodBoolean; + environment: z$1.ZodOptional; + projectId: z$1.ZodString; + hostId: z$1.ZodString; + path: z$1.ZodNullable; + managed: z$1.ZodBoolean; + isGitRepo: z$1.ZodBoolean; + isWorktree: z$1.ZodBoolean; + workspaceProvisionType: z$1.ZodEnum<{ + personal: "personal"; + "managed-worktree": "managed-worktree"; + unmanaged: "unmanaged"; + }>; + branchName: z$1.ZodNullable; + baseBranch: z$1.ZodNullable; + defaultBranch: z$1.ZodNullable; + mergeBaseBranch: z$1.ZodNullable; + status: z$1.ZodEnum<{ + error: "error"; + provisioning: "provisioning"; + ready: "ready"; + retiring: "retiring"; + destroying: "destroying"; + destroyed: "destroyed"; + }>; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + }, z$1.core.$strip>>>; + host: z$1.ZodOptional; + status: z$1.ZodEnum<{ + disconnected: "disconnected"; + connected: "connected"; + }>; + lastSeenAt: z$1.ZodNullable; + lastRejectedProtocolVersion: z$1.ZodNullable; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; + }, z$1.core.$strip>>>; +}, z$1.core.$strip>; +type ThreadWithIncludesResponse = z$1.infer; +declare const threadPendingInteractionsResponseSchema: z$1.ZodArray; + statusReason: z$1.ZodNullable; + createdAt: z$1.ZodNumber; + expiresAt: z$1.ZodOptional>; + resolvedAt: z$1.ZodNullable; + turnId: z$1.ZodString; + providerId: z$1.ZodString; + providerThreadId: z$1.ZodString; + providerRequestId: z$1.ZodString; + origin: z$1.ZodOptional; + providerId: z$1.ZodString; + providerThreadId: z$1.ZodString; + providerRequestId: z$1.ZodString; + }, z$1.core.$strip>>; + payload: z$1.ZodUnion; + subject: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + itemId: z$1.ZodString; + command: z$1.ZodString; + cwd: z$1.ZodNullable; + actions: z$1.ZodArray; + command: z$1.ZodString; + name: z$1.ZodString; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"listFiles">; + command: z$1.ZodString; + path: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"search">; + command: z$1.ZodString; + query: z$1.ZodNullable; + path: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + type: z$1.ZodLiteral<"unknown">; + command: z$1.ZodString; + }, z$1.core.$strip>], "type">>; + sessionGrant: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"file_change">; + itemId: z$1.ZodString; + writeScope: z$1.ZodNullable; + sessionGrant: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"permission_grant">; + itemId: z$1.ZodString; + toolName: z$1.ZodNullable; + permissions: z$1.ZodObject<{ + network: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>; + }, z$1.core.$strip>], "kind">; + reason: z$1.ZodNullable; + availableDecisions: z$1.ZodArray>; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"user_question">; + questions: z$1.ZodArray; + multiSelect: z$1.ZodBoolean; + options: z$1.ZodOptional; + }, z$1.core.$strip>>>; + allowFreeText: z$1.ZodBoolean; + }, z$1.core.$strip>>; + }, z$1.core.$strip>]>; + resolution: z$1.ZodNullable; + grantedPermissions: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + decision: z$1.ZodLiteral<"allow_for_session">; + grantedPermissions: z$1.ZodNullable; + }, z$1.core.$strip>>; + fileSystem: z$1.ZodNullable; + write: z$1.ZodArray; + }, z$1.core.$strip>>; + }, z$1.core.$strict>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + decision: z$1.ZodLiteral<"deny">; + }, z$1.core.$strip>], "decision">, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"user_answer">; + answers: z$1.ZodRecord; + freeText: z$1.ZodOptional; + }, z$1.core.$strip>>; + }, z$1.core.$strip>]>>; +}, z$1.core.$strip>, z$1.ZodObject<{ + id: z$1.ZodString; + threadId: z$1.ZodString; + status: z$1.ZodEnum<{ + pending: "pending"; + interrupted: "interrupted"; + resolving: "resolving"; + resolved: "resolved"; + }>; + statusReason: z$1.ZodNullable; + createdAt: z$1.ZodNumber; + expiresAt: z$1.ZodOptional>; + resolvedAt: z$1.ZodNullable; + turnId: z$1.ZodNullable; + origin: z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + rendererId: z$1.ZodString; + }, z$1.core.$strip>; + payload: z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + title: z$1.ZodString; + data: z$1.ZodType>; + }, z$1.core.$strip>; + resolution: z$1.ZodNullable; + }, z$1.core.$strip>>; +}, z$1.core.$strip>]>>; +type ThreadPendingInteractionsResponse = z$1.infer; +declare const threadQueuedMessageListResponseSchema: z$1.ZodArray>; + type: z$1.ZodLiteral<"text">; + text: z$1.ZodString; + mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"thread">; + threadId: z$1.ZodString; + projectId: z$1.ZodOptional; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"project">; + projectId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"section">; + sectionId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"path">; + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + entryKind: z$1.ZodEnum<{ + file: "file"; + directory: "directory"; + }>; + path: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"command">; + trigger: z$1.ZodEnum<{ + "/": "/"; + }>; + name: z$1.ZodString; + source: z$1.ZodEnum<{ + command: "command"; + skill: "skill"; + }>; + origin: z$1.ZodEnum<{ + user: "user"; + project: "project"; + builtin: "builtin"; + }>; + label: z$1.ZodString; + argumentHint: z$1.ZodNullable; + }, z$1.core.$strip>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"plugin">; + pluginId: z$1.ZodString; + icon: z$1.ZodOptional>; + itemId: z$1.ZodString; + label: z$1.ZodString; + }, z$1.core.$strip>], "kind">>; + }, z$1.core.$strip>>>; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"image">; + url: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localImage">; + path: z$1.ZodString; + }, z$1.core.$strip>, z$1.ZodObject<{ + visibility: z$1.ZodOptional>; + type: z$1.ZodLiteral<"localFile">; + path: z$1.ZodString; + name: z$1.ZodOptional; + sizeBytes: z$1.ZodOptional; + mimeType: z$1.ZodOptional; + }, z$1.core.$strip>], "type">>; + model: z$1.ZodString; + reasoningLevel: z$1.ZodEnum<{ + none: "none"; + low: "low"; + medium: "medium"; + high: "high"; + xhigh: "xhigh"; + ultracode: "ultracode"; + max: "max"; + ultra: "ultra"; + }>; + permissionMode: z$1.ZodEnum<{ + "accept-edits": "accept-edits"; + auto: "auto"; + full: "full"; + }>; + serviceTier: z$1.ZodEnum<{ + default: "default"; + fast: "fast"; + }>; + groupWithNext: z$1.ZodBoolean; + createdAt: z$1.ZodNumber; + updatedAt: z$1.ZodNumber; +}, z$1.core.$strip>>; +type ThreadQueuedMessageListResponse = z$1.infer; +declare const threadChildSummaryResponseSchema: z$1.ZodObject<{ + nonDeletedChildCount: z$1.ZodNumber; +}, z$1.core.$strip>; +type ThreadChildSummaryResponse = z$1.infer; +declare const deleteThreadRequestSchema: z$1.ZodObject<{ + childThreadsConfirmed: z$1.ZodBoolean; +}, z$1.core.$strip>; +type DeleteThreadRequest = z$1.infer; +declare const updateThreadRequestSchema: z$1.ZodObject<{ + title: z$1.ZodOptional>; + sectionId: z$1.ZodOptional>; + parentThreadId: z$1.ZodOptional>; + model: z$1.ZodOptional>; + reasoningLevel: z$1.ZodOptional>>; + visibility: z$1.ZodOptional>; +}, z$1.core.$strip>; +type UpdateThreadRequest = z$1.infer; +declare const reorderPinnedThreadRequestSchema: z$1.ZodObject<{ + previousThreadId: z$1.ZodNullable; + nextThreadId: z$1.ZodNullable; +}, z$1.core.$strip>; +type ReorderPinnedThreadRequest = z$1.infer; +/** + * Requested placement for a thread opened in the app's split layout. Edge + * placements add panes through the eighth pane; at the cap they replace the + * focused pane. `replace` always replaces the focused pane. + */ +declare const threadOpenSplitSchema: z$1.ZodEnum<{ + right: "right"; + down: "down"; + left: "left"; + top: "top"; + replace: "replace"; +}>; +type ThreadOpenSplit = z$1.infer; +/** Optional secondary-panel file to open with a thread. */ +declare const threadOpenFileSchema: z$1.ZodObject<{ + source: z$1.ZodEnum<{ + workspace: "workspace"; + "thread-storage": "thread-storage"; + }>; + path: z$1.ZodString; + lineNumber: z$1.ZodNullable; +}, z$1.core.$strict>; +type ThreadOpenFile = z$1.infer; +/** Response for POST /threads/:id/open: how many connected clients received it. */ +declare const threadOpenResponseSchema: z$1.ZodObject<{ + delivered: z$1.ZodNumber; +}, z$1.core.$strip>; +type ThreadOpenResponse = z$1.infer; +/** Presentation action for one thread pane in each connected app window. */ +declare const threadPaneActionSchema: z$1.ZodEnum<{ + maximize: "maximize"; + restore: "restore"; + toggle: "toggle"; +}>; +type ThreadPaneAction = z$1.infer; +/** Number of connected app clients that received the pane action. */ +declare const threadPaneActionResponseSchema: z$1.ZodObject<{ + delivered: z$1.ZodNumber; +}, z$1.core.$strip>; +type ThreadPaneActionResponse = z$1.infer; +declare const threadArchiveAllResponseSchema: z$1.ZodObject<{ + ok: z$1.ZodLiteral; + archivedThreadIds: z$1.ZodArray; +}, z$1.core.$strip>; +type ThreadArchiveAllResponse = z$1.infer; +declare const threadListQuerySchema: z$1.ZodObject<{ + projectId: z$1.ZodOptional; + parentThreadId: z$1.ZodOptional; + sourceThreadId: z$1.ZodOptional; + archived: z$1.ZodOptional>; + sectionId: z$1.ZodOptional; + unsectioned: z$1.ZodOptional>; + hasParent: z$1.ZodOptional>; + originKind: z$1.ZodOptional>; + excludeSideChats: z$1.ZodOptional>; + childOrigin: z$1.ZodOptional>; + includeHidden: z$1.ZodOptional>; + limit: z$1.ZodOptional; + offset: z$1.ZodOptional; +}, z$1.core.$strip>; +type ThreadListQuery = z$1.infer; +declare const threadSearchQuerySchema: z$1.ZodObject<{ + query: z$1.ZodString; + limitPerGroup: z$1.ZodOptional; +}, z$1.core.$strip>; +type ThreadSearchQuery = z$1.infer; +declare const threadTimelineQuerySchema: z$1.ZodObject<{ + includeNestedRows: z$1.ZodOptional>; + segmentLimit: z$1.ZodOptional; + beforeAnchorSeq: z$1.ZodOptional; + beforeAnchorId: z$1.ZodOptional; + summaryOnly: z$1.ZodOptional>; + afterSequence: z$1.ZodOptional; +}, z$1.core.$strip>; +type ThreadTimelineQuery = z$1.infer; +declare const timelineTurnSummaryDetailsQuerySchema: z$1.ZodObject<{ + turnId: z$1.ZodString; + sourceSeqStart: z$1.ZodString; + sourceSeqEnd: z$1.ZodString; +}, z$1.core.$strip>; +type TimelineTurnSummaryDetailsQuery = z$1.infer; +declare const threadStorageFilesQuerySchema: z$1.ZodObject<{ + query: z$1.ZodOptional; + limit: z$1.ZodOptional; +}, z$1.core.$strip>; +type ThreadStorageFilesQuery = z$1.infer; +declare const threadStoragePathsQuerySchema: z$1.ZodObject<{ + query: z$1.ZodOptional; + limit: z$1.ZodOptional; + includeFiles: z$1.ZodEnum<{ + true: "true"; + false: "false"; + }>; + includeDirectories: z$1.ZodEnum<{ + true: "true"; + false: "false"; + }>; +}, z$1.core.$strip>; +type ThreadStoragePathsQuery = z$1.infer; +declare const timelineTurnSummaryDetailsResponseSchema: z$1.ZodObject<{ + rows: z$1.ZodArray>>; +}, z$1.core.$strip>; +type TimelineTurnSummaryDetailsResponse = z$1.infer; +declare const threadTimelineResponseSchema: z$1.ZodObject<{ + rows: z$1.ZodArray>>; + activePromptMode: z$1.ZodNullable; + providerId: z$1.ZodEnum<{ + codex: "codex"; + "claude-code": "claude-code"; + }>; + prompt: z$1.ZodString; + }, z$1.core.$strict>>; + activeThinking: z$1.ZodNullable>; + activeWorkflow: z$1.ZodNullable; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"workflow">; + itemId: z$1.ZodString; + taskType: z$1.ZodString; + workflowName: z$1.ZodNullable; + description: z$1.ZodString; + taskStatus: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + running: "running"; + paused: "paused"; + failed: "failed"; + killed: "killed"; + stopped: "stopped"; + }>; + workflow: z$1.ZodNullable; + }, z$1.core.$strip>>; + agents: z$1.ZodArray; + model: z$1.ZodString; + attempt: z$1.ZodNumber; + cached: z$1.ZodBoolean; + lastProgressAt: z$1.ZodNumber; + phaseIndex: z$1.ZodOptional; + phaseTitle: z$1.ZodOptional; + agentType: z$1.ZodOptional; + isolation: z$1.ZodOptional; + queuedAt: z$1.ZodOptional; + startedAt: z$1.ZodOptional; + lastToolName: z$1.ZodOptional; + lastToolSummary: z$1.ZodOptional; + promptPreview: z$1.ZodOptional; + resultPreview: z$1.ZodOptional; + error: z$1.ZodOptional; + tokens: z$1.ZodOptional; + toolCalls: z$1.ZodOptional; + durationMs: z$1.ZodOptional; + }, z$1.core.$strip>>; + }, z$1.core.$strip>>; + usage: z$1.ZodNullable>; + summary: z$1.ZodNullable; + error: z$1.ZodNullable; + completedAt: z$1.ZodNullable; + }, z$1.core.$strip>>; + activeBackgroundCommands: z$1.ZodArray; + sourceSeqStart: z$1.ZodNumber; + sourceSeqEnd: z$1.ZodNumber; + startedAt: z$1.ZodNumber; + createdAt: z$1.ZodNumber; + kind: z$1.ZodLiteral<"work">; + status: z$1.ZodEnum<{ + error: "error"; + pending: "pending"; + completed: "completed"; + interrupted: "interrupted"; + }>; + workKind: z$1.ZodLiteral<"workflow">; + itemId: z$1.ZodString; + taskType: z$1.ZodString; + workflowName: z$1.ZodNullable; + description: z$1.ZodString; + taskStatus: z$1.ZodEnum<{ + pending: "pending"; + completed: "completed"; + running: "running"; + paused: "paused"; + failed: "failed"; + killed: "killed"; + stopped: "stopped"; + }>; + workflow: z$1.ZodNullable; + }, z$1.core.$strip>>; + agents: z$1.ZodArray; + model: z$1.ZodString; + attempt: z$1.ZodNumber; + cached: z$1.ZodBoolean; + lastProgressAt: z$1.ZodNumber; + phaseIndex: z$1.ZodOptional; + phaseTitle: z$1.ZodOptional; + agentType: z$1.ZodOptional; + isolation: z$1.ZodOptional; + queuedAt: z$1.ZodOptional; + startedAt: z$1.ZodOptional; + lastToolName: z$1.ZodOptional; + lastToolSummary: z$1.ZodOptional; + promptPreview: z$1.ZodOptional; + resultPreview: z$1.ZodOptional; + error: z$1.ZodOptional; + tokens: z$1.ZodOptional; + toolCalls: z$1.ZodOptional; + durationMs: z$1.ZodOptional; + }, z$1.core.$strip>>; + }, z$1.core.$strip>>; + usage: z$1.ZodNullable>; + summary: z$1.ZodNullable; + error: z$1.ZodNullable; + completedAt: z$1.ZodNullable; + }, z$1.core.$strip>>; + pendingTodos: z$1.ZodNullable; + }, z$1.core.$strip>>; + }, z$1.core.$strip>>; + goal: z$1.ZodNullable; + tokenBudget: z$1.ZodNullable; + tokensUsed: z$1.ZodNumber; + timeUsedSeconds: z$1.ZodNumber; + }, z$1.core.$strip>>; + modelFallback: z$1.ZodNullable; + message: z$1.ZodString; + }, z$1.core.$strip>>; + contextWindowUsage: z$1.ZodOptional>; + timelinePage: z$1.ZodObject<{ + kind: z$1.ZodEnum<{ + latest: "latest"; + older: "older"; + }>; + segmentLimit: z$1.ZodNumber; + returnedSegmentCount: z$1.ZodNumber; + hasOlderRows: z$1.ZodBoolean; + olderCursor: z$1.ZodNullable>; + }, z$1.core.$strict>; + maxSeq: z$1.ZodNumber; + delta: z$1.ZodOptional>>; + rowOrder: z$1.ZodOptional>; + }, z$1.core.$strip>>; +}, z$1.core.$strip>; +type ThreadTimelineResponse = z$1.infer; +declare const threadConversationOutlineResponseSchema: z$1.ZodObject<{ + items: z$1.ZodArray; + preview: z$1.ZodString; + attachmentSummary: z$1.ZodNullable>; + }, z$1.core.$strict>>; + maxSeq: z$1.ZodNumber; +}, z$1.core.$strict>; +type ThreadConversationOutlineResponse = z$1.infer; +declare const threadStorageFileListResponseSchema: z$1.ZodObject<{ + files: z$1.ZodArray>; + truncated: z$1.ZodBoolean; + storageRootPath: z$1.ZodString; +}, z$1.core.$strip>; +type ThreadStorageFileListResponse = z$1.infer; +declare const threadStoragePathListResponseSchema: z$1.ZodObject<{ + paths: z$1.ZodArray; + path: z$1.ZodString; + name: z$1.ZodString; + score: z$1.ZodNumber; + positions: z$1.ZodArray; + }, z$1.core.$strip>>; + truncated: z$1.ZodBoolean; + storageRootPath: z$1.ZodString; +}, z$1.core.$strip>; +type ThreadStoragePathListResponse = z$1.infer; + +declare const threadTabsResponseSchema: z$1.ZodObject<{ + revision: z$1.ZodNumber; + tabs: z$1.ZodArray; + }, z$1.core.$strict>, z$1.ZodObject<{ + id: z$1.ZodString; + kind: z$1.ZodLiteral<"git-diff">; + }, z$1.core.$strict>, z$1.ZodObject<{ + actionId: z$1.ZodString; + id: z$1.ZodString; + kind: z$1.ZodLiteral<"plugin-panel">; + paramsJson: z$1.ZodNullable; + pluginId: z$1.ZodString; + title: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodNullable; + id: z$1.ZodString; + kind: z$1.ZodLiteral<"workspace-file-preview">; + lineRange: z$1.ZodNullable>; + path: z$1.ZodString; + projectId: z$1.ZodNullable; + source: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"working-tree">; + }, z$1.core.$strict>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"head">; + }, z$1.core.$strict>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"merge-base">; + ref: z$1.ZodString; + }, z$1.core.$strict>], "kind">; + statusLabel: z$1.ZodNullable>; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodNullable; + id: z$1.ZodString; + kind: z$1.ZodLiteral<"host-file-preview">; + lineRange: z$1.ZodNullable>; + path: z$1.ZodString; + threadId: z$1.ZodNullable; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodNullable; + id: z$1.ZodString; + isPinned: z$1.ZodBoolean; + kind: z$1.ZodLiteral<"thread-storage-file-preview">; + lineRange: z$1.ZodNullable>; + path: z$1.ZodString; + threadId: z$1.ZodNullable; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodNullable; + id: z$1.ZodString; + kind: z$1.ZodLiteral<"browser">; + title: z$1.ZodNullable; + url: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + id: z$1.ZodString; + kind: z$1.ZodLiteral<"new-tab">; + }, z$1.core.$strict>, z$1.ZodObject<{ + id: z$1.ZodString; + kind: z$1.ZodLiteral<"side-chat">; + sourceMessageText: z$1.ZodString; + sourceSeqEnd: z$1.ZodNullable; + threadId: z$1.ZodNullable; + title: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + id: z$1.ZodString; + kind: z$1.ZodLiteral<"terminal">; + terminalId: z$1.ZodString; + }, z$1.core.$strict>], "kind">>; +}, z$1.core.$strict>; +type ThreadTabsResponse = z$1.infer; +declare const updateThreadTabsRequestSchema: z$1.ZodObject<{ + expectedRevision: z$1.ZodNumber; + tabs: z$1.ZodArray; + }, z$1.core.$strict>, z$1.ZodObject<{ + id: z$1.ZodString; + kind: z$1.ZodLiteral<"git-diff">; + }, z$1.core.$strict>, z$1.ZodObject<{ + actionId: z$1.ZodString; + id: z$1.ZodString; + kind: z$1.ZodLiteral<"plugin-panel">; + paramsJson: z$1.ZodNullable; + pluginId: z$1.ZodString; + title: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodNullable; + id: z$1.ZodString; + kind: z$1.ZodLiteral<"workspace-file-preview">; + lineRange: z$1.ZodNullable>; + path: z$1.ZodString; + projectId: z$1.ZodNullable; + source: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{ + kind: z$1.ZodLiteral<"working-tree">; + }, z$1.core.$strict>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"head">; + }, z$1.core.$strict>, z$1.ZodObject<{ + kind: z$1.ZodLiteral<"merge-base">; + ref: z$1.ZodString; + }, z$1.core.$strict>], "kind">; + statusLabel: z$1.ZodNullable>; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodNullable; + id: z$1.ZodString; + kind: z$1.ZodLiteral<"host-file-preview">; + lineRange: z$1.ZodNullable>; + path: z$1.ZodString; + threadId: z$1.ZodNullable; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodNullable; + id: z$1.ZodString; + isPinned: z$1.ZodBoolean; + kind: z$1.ZodLiteral<"thread-storage-file-preview">; + lineRange: z$1.ZodNullable>; + path: z$1.ZodString; + threadId: z$1.ZodNullable; + }, z$1.core.$strict>, z$1.ZodObject<{ + environmentId: z$1.ZodNullable; + id: z$1.ZodString; + kind: z$1.ZodLiteral<"browser">; + title: z$1.ZodNullable; + url: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + id: z$1.ZodString; + kind: z$1.ZodLiteral<"new-tab">; + }, z$1.core.$strict>, z$1.ZodObject<{ + id: z$1.ZodString; + kind: z$1.ZodLiteral<"side-chat">; + sourceMessageText: z$1.ZodString; + sourceSeqEnd: z$1.ZodNullable; + threadId: z$1.ZodNullable; + title: z$1.ZodString; + }, z$1.core.$strict>, z$1.ZodObject<{ + id: z$1.ZodString; + kind: z$1.ZodLiteral<"terminal">; + terminalId: z$1.ZodString; + }, z$1.core.$strict>], "kind">>; +}, z$1.core.$strict>; +type UpdateThreadTabsRequest = z$1.infer; + +interface EnvironmentActionArgs { + environmentId: string; +} +interface EnvironmentGetArgs extends EnvironmentActionArgs { + signal?: AbortSignal; +} +type EnvironmentMergeBaseBranchUpdateValue = Exclude; +type EnvironmentNameUpdateValue = Exclude; +interface EnvironmentMergeBaseBranchUpdate { + mergeBaseBranch: EnvironmentMergeBaseBranchUpdateValue; + name?: EnvironmentNameUpdateValue; +} +interface EnvironmentNameUpdate { + mergeBaseBranch?: EnvironmentMergeBaseBranchUpdateValue; + name: EnvironmentNameUpdateValue; +} +type EnvironmentUpdateFields = EnvironmentMergeBaseBranchUpdate | EnvironmentNameUpdate; +type EnvironmentUpdateArgs = EnvironmentUpdateFields & { + environmentId: string; +}; +interface EnvironmentStatusArgs extends EnvironmentStatusQuery { + environmentId: string; + signal?: AbortSignal; +} +type EnvironmentDiffArgs = EnvironmentDiffQuery & { + environmentId: string; + signal?: AbortSignal; +}; +type EnvironmentDiffFileArgs = EnvironmentDiffFileQuery & { + environmentId: string; + signal?: AbortSignal; +}; +interface EnvironmentDiffBranchesArgs extends EnvironmentDiffBranchesQuery { + environmentId: string; + signal?: AbortSignal; +} +interface EnvironmentCommitArgs { + environmentId: string; +} +interface EnvironmentSquashMergeArgs { + environmentId: string; + mergeBaseBranch: string; +} +interface EnvironmentPullRequestMergeArgs { + environmentId: string; + method: PullRequestMergeMethod; +} +type EnvironmentDiffPatchArgs = EnvironmentDiffPatchRequest & { + environmentId: string; + signal?: AbortSignal; +}; +interface EnvironmentPathsArgs extends EnvironmentPathsQuery { + environmentId: string; + signal?: AbortSignal; +} +type EnvironmentArchiveThreadsResult = EnvironmentArchiveThreadsResponse; +type EnvironmentCommitResult = CommitActionResponse; +type EnvironmentDiffResult = EnvironmentDiffResponse; +type EnvironmentDiffBranchesResult = EnvironmentDiffBranchesResponse; +type EnvironmentDiffFileResult = EnvironmentDiffFileResponse; +type EnvironmentDiffFilesResult = EnvironmentDiffFilesResponse; +type EnvironmentDiffPatchResult = EnvironmentDiffPatchResponse; +type EnvironmentGetResult = Environment; +type EnvironmentMarkPullRequestDraftResult = PullRequestDraftActionResponse; +type EnvironmentMarkPullRequestReadyResult = PullRequestReadyActionResponse; +type EnvironmentMergePullRequestResult = PullRequestMergeActionResponse; +type EnvironmentPathsResult = WorkspacePathListResponse; +type EnvironmentPullRequestResult = EnvironmentPullRequestResponse; +type EnvironmentSquashMergeResult = SquashMergeActionResponse; +type EnvironmentStatusResult = EnvironmentStatusResponse; +type EnvironmentUpdateResult = Environment; +interface EnvironmentsArea { + archiveThreads(args: EnvironmentActionArgs): Promise; + commit(args: EnvironmentCommitArgs): Promise; + diff(args: EnvironmentDiffArgs): Promise; + diffBranches(args: EnvironmentDiffBranchesArgs): Promise; + diffFile(args: EnvironmentDiffFileArgs): Promise; + diffFiles(args: EnvironmentDiffArgs): Promise; + diffPatch(args: EnvironmentDiffPatchArgs): Promise; + get(args: EnvironmentGetArgs): Promise; + pullRequest(args: EnvironmentGetArgs): Promise; + markPullRequestDraft(args: EnvironmentActionArgs): Promise; + markPullRequestReady(args: EnvironmentActionArgs): Promise; + mergePullRequest(args: EnvironmentPullRequestMergeArgs): Promise; + paths(args: EnvironmentPathsArgs): Promise; + squashMerge(args: EnvironmentSquashMergeArgs): Promise; + status(args: EnvironmentStatusArgs): Promise; + update(args: EnvironmentUpdateArgs): Promise; +} + +/** + * Host file primitives. `hostId` may be omitted to target the server's + * primary (local) host. `rootPath`, when set, confines the target beneath + * that absolute root on the host (symlink-safe). + */ +interface FileReadArgs { + hostId?: string; + path: string; + rootPath?: string; + signal?: AbortSignal; +} +interface FileWriteArgs { + hostId?: string; + path: string; + rootPath?: string; + content: string; + /** Defaults to "utf8". */ + contentEncoding?: "utf8" | "base64"; + /** Defaults to false. */ + createParents?: boolean; + /** + * Optimistic-concurrency guard: omitted → unconditional write; a hash → + * write only when the current content hashes to it (use `read().sha256`); + * null → create-only. A failed guard resolves to the `conflict` outcome. + */ + expectedSha256?: string | null; + /** POSIX permission bits used when creating a file (for example 0o600). */ + mode?: number; +} +interface FileListArgs { + hostId?: string; + path: string; + query?: string; + limit?: number; + signal?: AbortSignal; +} +interface PathListArgs extends FileListArgs { + includeFiles: boolean; + includeDirectories: boolean; +} +interface FileMkdirArgs { + hostId?: string; + path: string; + rootPath?: string; + recursive?: boolean; +} +interface FileMoveArgs { + hostId?: string; + sourcePath: string; + destinationPath: string; + rootPath?: string; +} +interface FileRemoveArgs { + hostId?: string; + path: string; + rootPath?: string; + recursive?: boolean; +} +interface FilePreviewArgs { + hostId?: string; + rootPath: string; + signal?: AbortSignal; + ttlMs?: number; +} +type FileReadResult = HostFileReadResponse; +type FileWriteResult = HostFileWriteResponse; +type FileListResult = HostFileListResponse; +type PathListResult = HostPathListResponse; +type FileMkdirResult = HostMkdirResponse; +type FileMoveResult = HostMovePathResponse; +type FileRemoveResult = HostRemovePathResponse; +type FilePreviewResult = CreateFilePreviewResponse; +interface FilesArea { + read(args: FileReadArgs): Promise; + write(args: FileWriteArgs): Promise; + list(args: FileListArgs): Promise; + listPaths(args: PathListArgs): Promise; + mkdir(args: FileMkdirArgs): Promise; + move(args: FileMoveArgs): Promise; + remove(args: FileRemoveArgs): Promise; + createPreview(args: FilePreviewArgs): Promise; +} + +interface GuideRenderArgs { + chapter?: string; +} +interface GuideRenderResult { + chapter?: string; + content: string; +} +interface GuideArea { + render(args?: GuideRenderArgs): GuideRenderResult; +} + +interface HostGetArgs { + hostId: string; + signal?: AbortSignal; +} +interface HostDeleteArgs { + hostId: string; +} +interface HostUpdateArgs extends UpdateHostRequest { + hostId: string; +} +interface HostRetryUpdateArgs { + hostId: string; +} +interface HostDirectoryArgs extends HostDirectoryQuery { + hostId: string; + signal?: AbortSignal; +} +interface HostCloneDefaultPathArgs extends HostCloneDefaultPathQuery { + hostId: string; + signal?: AbortSignal; +} +interface HostPathsExistArgs extends HostPathsExistRequest { + hostId: string; + signal?: AbortSignal; +} +interface HostPickFolderArgs extends HostPickFolderRequest { + hostId: string; + signal?: AbortSignal; +} +interface HostProviderCliInstallArgs extends HostProviderCliInstallRequest { + hostId: string; +} +interface HostListArgs { + signal?: AbortSignal; +} +type HostCreateJoinCodeResult = CreateHostJoinCodeResponse; +type HostDeleteResult = { + ok: true; +}; +type HostDirectoryResult = HostDirectoryListing; +type HostGetResult = Host; +type HostCloneDefaultPathResult = HostCloneDefaultPathResponse; +type HostProviderCliInstallResult = HostProviderCliInstallEvent[]; +type HostListResult = Host[]; +type HostPathsExistResult = HostPathsExistResponse; +type HostPickFolderResult = HostPickFolderResponse; +type HostProviderCliStatusResult = HostProviderCliStatusResponse; +type HostRetryUpdateResult = HostRetryUpdateResponse; +type HostUpdateResult = Host; +interface HostsArea { + createJoinCode(): Promise; + delete(args: HostDeleteArgs): Promise; + directory(args: HostDirectoryArgs): Promise; + get(args: HostGetArgs): Promise; + cloneDefaultPath(args: HostCloneDefaultPathArgs): Promise; + installProviderCli(args: HostProviderCliInstallArgs): Promise; + list(args?: HostListArgs): Promise; + pathsExist(args: HostPathsExistArgs): Promise; + pickFolder(args: HostPickFolderArgs): Promise; + providerCliStatus(args: HostGetArgs): Promise; + retryUpdate(args: HostRetryUpdateArgs): Promise; + update(args: HostUpdateArgs): Promise; +} + +interface ProjectListArgs { + include?: ProjectListQuery["include"]; + /** Include the singleton personal project. Defaults to false for compatibility. */ + includePersonal?: boolean; + signal?: AbortSignal; +} +interface ProjectCreateArgs extends CreateProjectRequest { +} +interface ProjectGetArgs { + projectId: string; + signal?: AbortSignal; +} +interface ProjectUpdateArgs extends UpdateProjectRequest { + projectId: string; +} +interface ProjectDeleteArgs { + projectId: string; +} +interface ProjectReorderArgs extends ReorderProjectRequest { + projectId: string; +} +interface ProjectPromptHistoryArgs extends PromptHistoryQuery { + projectId: string; + signal?: AbortSignal; +} +/** Select one project workspace source, or omit both for the primary host. */ +type ProjectWorkspaceRoutingArgs = { + environmentId: string; + hostId?: never; +} | { + environmentId?: never; + hostId: string; +} | { + environmentId?: never; + hostId?: never; +}; +type ProjectFilesArgs = ProjectWorkspaceRoutingArgs & Omit & { + projectId: string; + signal?: AbortSignal; +}; +type ProjectPathsArgs = ProjectWorkspaceRoutingArgs & Omit & { + projectId: string; + signal?: AbortSignal; +}; +type ProjectCommandsArgs = ProjectWorkspaceRoutingArgs & Omit & { + projectId: string; + signal?: AbortSignal; +}; +type ProjectFileContentArgs = ProjectWorkspaceRoutingArgs & Omit & { + projectId: string; + signal?: AbortSignal; +}; +interface ProjectBranchesArgs extends ProjectBranchesQuery { + projectId: string; + signal?: AbortSignal; +} +interface ProjectDefaultExecutionOptionsArgs { + projectId: string; + signal?: AbortSignal; +} +interface ProjectAttachmentFileLike { + arrayBuffer(): Promise; + readonly name: string; + readonly type?: string; +} +interface ProjectAttachmentUploadArgsBase { + /** MIME override. Omit to use the File/Blob type, when available. */ + mimeType?: string; + projectId: string; +} +/** + * Upload bytes owned by this SDK client. A bare Blob/byte buffer needs an + * explicit filename; File-like values can supply their own name. + */ +type ProjectAttachmentUploadArgs = ProjectAttachmentUploadArgsBase & ({ + clientFile: ProjectAttachmentFileLike; + filename?: string; +} | { + clientFile: ArrayBuffer | Blob | Uint8Array; + filename: string; +}); +interface ProjectAttachmentReadArgs { + path: string; + projectId: string; + signal?: AbortSignal; +} +interface ProjectAttachmentCopyArgs extends CopyProjectAttachmentsRequest { + projectId: string; +} +type ProjectSourceAddArgs = CreateProjectSourceRequest & { + projectId: string; +}; +interface ProjectSourceUpdateArgs extends UpdateProjectSourceRequest { + projectId: string; + sourceId: string; +} +interface ProjectSourceDeleteArgs { + projectId: string; + sourceId: string; +} +type ProjectBranchesResult = ProjectBranchesResponse; +interface ProjectAttachmentReadResult { + bytes: Uint8Array; + mimeType: string; + sizeBytes: number; +} +type ProjectAttachmentUploadResult = UploadedPromptAttachment; +type ProjectCommandsResult = CommandListResponse; +type ProjectCreateResult = ProjectResponse; +type ProjectDefaultExecutionOptionsResult = ProjectExecutionDefaults | null; +type ProjectDeleteResult = { + ok: true; +}; +interface ProjectFileContentResult { + /** UTF-8 text or base64, as selected by `contentEncoding`. */ + content: string; + contentEncoding: "utf8" | "base64"; + mimeType: string; + sizeBytes: number; +} +type ProjectFilesResult = WorkspaceFileListResponse; +type ProjectGetResult = ProjectResponse; +type ProjectListResult = ProjectResponse[] | ProjectWithThreadsResponse[]; +type ProjectPathsResult = WorkspacePathListResponse; +type ProjectPromptHistoryResult = PromptHistoryResponse; +type ProjectReorderResult = ProjectResponse[]; +type ProjectSourceAddResult = ProjectSource; +type ProjectSourceDeleteResult = { + ok: true; +}; +type ProjectSourceUpdateResult = ProjectSource; +type ProjectUpdateResult = ProjectResponse; +interface ProjectSourcesArea { + add(args: ProjectSourceAddArgs): Promise; + delete(args: ProjectSourceDeleteArgs): Promise; + update(args: ProjectSourceUpdateArgs): Promise; +} +interface ProjectAttachmentsArea { + copy(args: ProjectAttachmentCopyArgs): Promise; + read(args: ProjectAttachmentReadArgs): Promise; + upload(args: ProjectAttachmentUploadArgs): Promise; +} +interface ProjectsArea { + attachments: ProjectAttachmentsArea; + branches(args: ProjectBranchesArgs): Promise; + commands(args: ProjectCommandsArgs): Promise; + create(args: ProjectCreateArgs): Promise; + defaultExecutionOptions(args: ProjectDefaultExecutionOptionsArgs): Promise; + delete(args: ProjectDeleteArgs): Promise; + fileContent(args: ProjectFileContentArgs): Promise; + files(args: ProjectFilesArgs): Promise; + get(args: ProjectGetArgs): Promise; + list(args?: ProjectListArgs): Promise; + paths(args: ProjectPathsArgs): Promise; + promptHistory(args: ProjectPromptHistoryArgs): Promise; + reorder(args: ProjectReorderArgs): Promise; + sources: ProjectSourcesArea; + update(args: ProjectUpdateArgs): Promise; +} + +/** Select exactly one provider-discovery host source, or omit both for primary. */ +type ProviderHostRoutingArgs = { + environmentId: string; + hostId?: never; +} | { + environmentId?: never; + hostId: string; +} | { + environmentId?: never; + hostId?: never; +}; +type ProviderListArgs = ProviderHostRoutingArgs & { + signal?: AbortSignal; +}; +type ProviderModelsArgs = ProviderHostRoutingArgs & { + providerId?: string; + signal?: AbortSignal; +}; +type ProviderListResult = ProviderInfo[]; +type ProviderModelsResult = SystemExecutionOptionsResponse; +interface ProvidersArea { + /** List providers on the environment host, explicit host, or primary host. */ + list(args?: ProviderListArgs): Promise; + /** List models on the environment host, explicit host, or primary host. */ + models(args?: ProviderModelsArgs): Promise; +} + +interface PluginIdArgs { + pluginId: string; +} +/** Install directly from a path:, git:, npm:, or builtin: source spec. */ +interface PluginInstallArgs { + source: string; +} +/** Install an entry from BB's official catalog. */ +interface PluginCatalogInstallArgs { + entryId: string; +} +interface PluginReloadArgs { + pluginId?: string; +} +interface PluginSettingsUpdateArgs extends PluginIdArgs { + values: Record; +} +interface PluginTokenArgs extends PluginIdArgs { + rotate?: boolean; +} +interface PluginCheckUpdatesArgs { + pluginId?: string; + signal?: AbortSignal; +} +interface PluginRpcArgs extends PluginIdArgs { + input?: JsonValue; + method: string; + outputSchema: z$1.ZodType; +} +interface PluginCatalogSearchArgs { + query: string; + signal?: AbortSignal; +} +interface PluginCatalogStatusArgs { + signal?: AbortSignal; +} +interface PluginGetSettingsArgs extends PluginIdArgs { + signal?: AbortSignal; +} +interface PluginGetSourceArgs extends PluginIdArgs { + signal?: AbortSignal; +} +interface PluginListArgs { + signal?: AbortSignal; +} +interface PluginListUpdateResultsArgs { + signal?: AbortSignal; +} +type PluginDisableResult = InstalledPlugin; +type PluginEnableResult = InstalledPlugin; +type PluginGetSettingsResult = PluginSettingsResponse; +type PluginInstallResult = InstalledPlugin; +type PluginListResult = PluginListResponse; +type PluginReloadResult = PluginReloadResponse; +type PluginRemoveResult = PluginRemoveResponse; +type PluginTokenResult = PluginTokenResponse; +type PluginUpdateSettingsResult = PluginSettingsResponse; +type PluginGetSourceResult = PluginSourceDetail; +type PluginCheckUpdatesResult = PluginUpdateCheckEntry[]; +type PluginApplyUpdateResult = PluginApplyUpdateResult$1; +type PluginCatalogStatusResult = PluginCatalogStatus; +type PluginCatalogSearchResult = PluginCatalogSearchResult$1[]; +interface PluginCatalogArea { + install(args: PluginCatalogInstallArgs): Promise; + search(args: PluginCatalogSearchArgs): Promise; + status(args?: PluginCatalogStatusArgs): Promise; +} +interface PluginsArea { + applyUpdate(args: PluginIdArgs): Promise; + callRpc(args: PluginRpcArgs): Promise; + checkUpdates(args?: PluginCheckUpdatesArgs): Promise; + catalog: PluginCatalogArea; + disable(args: PluginIdArgs): Promise; + enable(args: PluginIdArgs): Promise; + getSettings(args: PluginGetSettingsArgs): Promise; + getSource(args: PluginGetSourceArgs): Promise; + install(args: PluginInstallArgs): Promise; + list(args?: PluginListArgs): Promise; + listUpdateResults(args?: PluginListUpdateResultsArgs): Promise; + reload(args?: PluginReloadArgs): Promise; + remove(args: PluginIdArgs): Promise; + token(args: PluginTokenArgs): Promise; + updateSettings(args: PluginSettingsUpdateArgs): Promise; +} + +type BbRealtimeUnsubscribe = () => void; +type BbRealtimeEventName = "thread:changed" | "project:changed" | "environment:changed" | "host:changed" | "system:changed" | "system:config-changed" | "realtime:connection"; +type ThreadRealtimeEvent = Extract; +type ProjectRealtimeEvent = Extract; +type EnvironmentRealtimeEvent = Extract; +type HostRealtimeEvent = Extract; +type SystemRealtimeEvent = Extract; +type BbRealtimeConnectionState = "connecting" | "connected" | "disconnected"; +interface BbRealtimeConnectionEvent { + reconnectDelayMs: number | null; + reconnected: boolean; + state: BbRealtimeConnectionState; +} +/** + * Entity-changed events are delivered as one shared object to every matching + * listener; their payload types are readonly so a listener cannot mutate what + * the next listener receives. + */ +interface BbRealtimeEventMap { + "thread:changed": ThreadRealtimeEvent; + "project:changed": ProjectRealtimeEvent; + "environment:changed": EnvironmentRealtimeEvent; + "host:changed": HostRealtimeEvent; + "system:changed": SystemRealtimeEvent; + "system:config-changed": SystemRealtimeEvent; + "realtime:connection": BbRealtimeConnectionEvent; +} +type BbRealtimeCallback = (event: BbRealtimeEventMap[TEventName]) => void; +interface ThreadRealtimeSubscribeArgs { + callback: BbRealtimeCallback<"thread:changed">; + event: "thread:changed"; + threadId?: string; +} +interface ProjectRealtimeSubscribeArgs { + callback: BbRealtimeCallback<"project:changed">; + event: "project:changed"; + projectId?: string; +} +interface EnvironmentRealtimeSubscribeArgs { + callback: BbRealtimeCallback<"environment:changed">; + environmentId?: string; + event: "environment:changed"; +} +interface HostRealtimeSubscribeArgs { + callback: BbRealtimeCallback<"host:changed">; + event: "host:changed"; + hostId?: string; +} +interface SystemRealtimeSubscribeArgs { + callback: BbRealtimeCallback<"system:changed">; + event: "system:changed"; +} +interface SystemConfigRealtimeSubscribeArgs { + callback: BbRealtimeCallback<"system:config-changed">; + event: "system:config-changed"; +} +/** + * Connection listeners are pure observers — they never open or hold the + * socket. A listener registered while a socket already exists receives the + * latest connection event as a snapshot on the next microtask, so a status + * UI mounted after connect still learns the current state. + */ +interface RealtimeConnectionSubscribeArgs { + callback: BbRealtimeCallback<"realtime:connection">; + event: "realtime:connection"; +} +type BbRealtimeSubscribeArgsUnion = ThreadRealtimeSubscribeArgs | ProjectRealtimeSubscribeArgs | EnvironmentRealtimeSubscribeArgs | HostRealtimeSubscribeArgs | SystemRealtimeSubscribeArgs | SystemConfigRealtimeSubscribeArgs | RealtimeConnectionSubscribeArgs; +type BbRealtimeSubscribeArgs = Extract; +interface BbRealtime { + subscribe(args: BbRealtimeSubscribeArgs): BbRealtimeUnsubscribe; +} + +interface StatusGetArgs { + projectId?: string; + signal?: AbortSignal; + threadId?: string; +} +interface StatusThreadSummary { + environmentId: string | null; + id: string; + parentThreadId: string | null; + pinnedAt: number | null; + projectId: string; + status: ThreadStatus; + title: string | null; +} +type StatusProject = ProjectResponse; +type StatusChildThreads = ThreadListResponse; +interface StatusResult { + childThreads: StatusChildThreads | null; + pendingTodos: ThreadTimelinePendingTodos | null; + project: StatusProject | null; + thread: StatusThreadSummary | null; +} +interface StatusArea { + get(args?: StatusGetArgs): Promise; +} + +type ThemeGetResult = AppTheme; +type ThemeCatalogResult = ThemeCatalogResponse; +type ThemeSetInput = AppThemeSelection; +type ThemeSetResult = AppTheme; +interface ThemeCatalogArgs { + signal?: AbortSignal; +} +interface ThemeGetArgs { + signal?: AbortSignal; +} +interface ThemeArea { + /** The active app palette, resolved server-side (built-in id or custom CSS). */ + get(args?: ThemeGetArgs): Promise; + /** The custom-theme directory plus discovered themes and the active palette. */ + catalog(args?: ThemeCatalogArgs): Promise; + /** Set the complete app appearance selection in one request. */ + set(selection: ThemeSetInput): Promise; + /** + * Activate a palette by id while preserving the active favicon color. This + * compatibility shorthand reads the active appearance before writing the + * complete selection; prefer the object form when both values are known. + */ + set(themeId: string): Promise; +} + +interface SystemAttentionArgs { + signal?: AbortSignal; +} +interface SystemConfigArgs { + signal?: AbortSignal; +} +interface SystemExecutionOptionsArgs extends SystemExecutionOptionsQuery { + signal?: AbortSignal; +} +interface SystemUsageLimitsArgs extends SystemUsageLimitsQuery { + signal?: AbortSignal; +} +interface SystemVersionArgs { + force?: boolean; + signal?: AbortSignal; +} +interface SystemVoiceTranscriptionArgs { + file: Blob; + prompt?: string; + signal?: AbortSignal; +} +type SystemAttentionResult = SystemAttentionResponse; +type SystemConfigResult = SystemConfigResponse; +type SystemExecutionOptionsResult = SystemExecutionOptionsResponse; +type SystemReloadConfigResult = SystemConfigReloadResponse; +type SystemVoiceTranscriptionResult = SystemVoiceTranscriptionResponse; +type SystemUpdateExperimentsResult = Experiments; +type SystemUpdateGeneralSettingsResult = AppSettings; +type SystemUpdateKeyboardSettingsResult = AppKeybindingOverrides; +type SystemUsageLimitsResult = ProviderUsageResponse; +type SystemVersionResult = SystemVersionResponse; +interface SystemArea { + attention(args?: SystemAttentionArgs): Promise; + config(args?: SystemConfigArgs): Promise; + executionOptions(args?: SystemExecutionOptionsArgs): Promise; + reloadConfig(): Promise; + transcribeVoice(args: SystemVoiceTranscriptionArgs): Promise; + updateExperiments(args: Experiments): Promise; + updateGeneralSettings(args: AppSettings): Promise; + updateKeyboardSettings(args: AppKeybindingOverrides): Promise; + usageLimits(args?: SystemUsageLimitsArgs): Promise; + version(args?: SystemVersionArgs): Promise; +} + +interface TerminalThreadScope { + cwd?: never; + environmentId?: never; + hostId?: never; + kind: "thread"; + threadId: string; +} +interface TerminalEnvironmentScope { + environmentId: string; + cwd?: never; + hostId?: never; + kind: "environment"; + threadId?: never; +} +interface TerminalHostPathListScope { + /** Optional exact initial working-directory filter on the selected host. */ + cwd?: string; + environmentId?: never; + hostId: string; + kind: "host_path"; + threadId?: never; +} +interface TerminalHostPathCreateScope { + /** Null starts in the selected host's home directory. */ + cwd: string | null; + environmentId?: never; + hostId: string; + kind: "host_path"; + threadId?: never; +} +type TerminalListScope = TerminalThreadScope | TerminalEnvironmentScope | TerminalHostPathListScope; +type TerminalCreateScope = TerminalThreadScope | TerminalEnvironmentScope | TerminalHostPathCreateScope; +interface TerminalListArgs { + signal?: AbortSignal; + scope: TerminalListScope; +} +interface TerminalCreateArgs { + cols: number; + rows: number; + scope: TerminalCreateScope; + start?: CreateTerminalRequest["start"]; + title?: string; +} +interface TerminalTargetArgs { + terminalId: string; +} +interface TerminalGetArgs extends TerminalTargetArgs { + signal?: AbortSignal; +} +interface TerminalRenameArgs extends TerminalTargetArgs { + title: UpdateTerminalRequest["title"]; +} +interface TerminalCloseArgs extends TerminalTargetArgs { + mode: "force" | "if-clean"; +} +interface TerminalInputArgs extends TerminalTargetArgs { + dataBase64: TerminalInputRequest["dataBase64"]; +} +interface TerminalResizeArgs extends TerminalTargetArgs { + cols: TerminalResizeRequest["cols"]; + rows: TerminalResizeRequest["rows"]; +} +interface TerminalOutputArgs extends TerminalTargetArgs { + limitChunks?: TerminalOutputQuery["limitChunks"]; + signal?: AbortSignal; + sinceSeq?: TerminalOutputQuery["sinceSeq"]; + tailBytes?: TerminalOutputQuery["tailBytes"]; +} +type TerminalRestartArgs = TerminalTargetArgs; +type TerminalListResult = TerminalListResponse; +type TerminalCreateResult = TerminalSession; +type TerminalGetResult = TerminalSession; +type TerminalRenameResult = TerminalSession; +type TerminalCloseResult = TerminalSession; +type TerminalInputResult = TerminalSession; +type TerminalResizeResult = TerminalSession; +type TerminalOutputResult = TerminalOutputResponse; +type TerminalRestartResult = TerminalSession; +interface TerminalsArea { + close(args: TerminalCloseArgs): Promise; + create(args: TerminalCreateArgs): Promise; + get(args: TerminalGetArgs): Promise; + input(args: TerminalInputArgs): Promise; + list(args: TerminalListArgs): Promise; + output(args: TerminalOutputArgs): Promise; + rename(args: TerminalRenameArgs): Promise; + /** + * Replace a terminal with a shell at the same scope, size, and title. + * The original command is not replayed because terminal sessions do not + * persist launch commands. The replacement has a new terminal ID. + */ + restart(args: TerminalRestartArgs): Promise; + resize(args: TerminalResizeArgs): Promise; +} + +interface ThreadListArgs { + archived?: boolean; + excludeSideChats?: boolean; + sectionId?: string; + hasParent?: boolean; + includeHidden?: boolean; + limit?: number; + offset?: number; + originKind?: ThreadListQuery["originKind"]; + parentThreadId?: string; + projectId?: string; + signal?: AbortSignal; + sourceThreadId?: string; + unsectioned?: boolean; +} +interface ThreadSearchArgs extends ThreadSearchQuery { + signal?: AbortSignal; +} +interface ThreadGetArgs { + include?: ThreadGetQuery["include"]; + signal?: AbortSignal; + threadId: string; +} +type ThreadGetResult = ThreadResponse | ThreadWithIncludesResponse; +type ThreadListResult = ThreadListResponse; +type ThreadSearchResult = ThreadSearchResponse; +interface ThreadOutputResponse { + output: string | null; +} +type ThreadMutationResult = ThreadResponse; +type ThreadSpawnResult = ThreadResponse; +type ThreadForkResult = ThreadResponse; +type ThreadInteractionGetResult = PendingInteraction; +type ThreadInteractionListResult = ThreadPendingInteractionsResponse; +type ThreadInteractionResolveResult = PendingInteraction; +type ThreadInteractionRespondResult = PendingInteraction; +type ThreadInteractionCancelResult = PendingInteraction; +type ThreadEventsListResult = ThreadEventRow[]; +type ThreadEventWaitResult = ThreadEventRow | null; +type ThreadTimelineResult = ThreadTimelineResponse; +type ThreadArchiveResult = ThreadArchiveAllResponse; +type ThreadOpenResult = ThreadOpenResponse; +type ThreadPaneActionResult = ThreadPaneActionResponse; +type ThreadDeleteResult = { + ok: true; +}; +type ThreadSendResult = { + ok: true; +}; +type ThreadStopResult = { + ok: true; +}; +type ThreadBannerActionResult = { + ok: true; +}; +type ThreadUnarchiveResult = { + ok: true; +}; +type ThreadArchiveAllResult = ThreadArchiveAllResponse; +type ThreadReadStateResult = ThreadResponse; +type ThreadPinOrderResult = ThreadListResponse; +type ThreadPromptHistoryResult = PromptHistoryResponse; +type ThreadQueuedMessagesResult = ThreadQueuedMessageListResponse; +type ThreadQueuedMessageCreateResult = ThreadQueuedMessage; +type ThreadQueuedMessageUpdateResult = ThreadQueuedMessage; +type ThreadQueuedMessageDeleteResult = { + ok: true; +}; +type ThreadQueuedMessageReorderResult = ThreadQueuedMessageListResponse; +type ThreadQueuedMessageSendResult = SendQueuedMessageResponse; +type ThreadQueuedMessageGroupBoundaryResult = ThreadQueuedMessageListResponse; +type ThreadTabsResult = ThreadTabsResponse; +type ThreadTabsUpdateResult = ThreadTabsResponse; +type ThreadStorageFilesResult = ThreadStorageFileListResponse; +type ThreadStoragePathsResult = ThreadStoragePathListResponse; +type ThreadChildSummaryResult = ThreadChildSummaryResponse; +type ThreadDefaultExecutionOptionsResult = ResolvedThreadExecutionOptions | null; +type ThreadConversationOutlineResult = ThreadConversationOutlineResponse; +type ThreadTimelineTurnSummaryDetailsResult = TimelineTurnSummaryDetailsResponse; +interface ThreadSpawnBaseArgs extends Omit { + childOrigin?: CreateThreadRequest["childOrigin"]; + origin?: CreateThreadRequest["origin"]; + originKind?: CreateThreadRequest["originKind"]; + startedOnBehalfOf?: CreateThreadRequest["startedOnBehalfOf"]; +} +type ThreadSpawnArgs = ThreadSpawnBaseArgs & ({ + input: CreateThreadRequest["input"]; + prompt?: never; +} | { + input?: never; + prompt: string; +}); +interface ThreadForkArgs extends Omit { + origin?: ForkThreadRequest["origin"]; + visibility?: ForkThreadRequest["visibility"]; + workspace?: ForkThreadRequest["workspace"]; +} +interface ThreadUpdateArgs extends UpdateThreadRequest { + threadId: string; +} +interface ThreadDeleteArgs extends DeleteThreadRequest { + threadId: string; +} +interface ThreadSendArgs extends SendMessageRequest { + threadId: string; +} +interface ThreadActionArgs { + threadId: string; +} +interface ThreadStatusArgs extends ThreadActionArgs { + signal?: AbortSignal; +} +interface ThreadPromptHistoryArgs extends PromptHistoryQuery { + signal?: AbortSignal; + threadId: string; +} +interface ThreadPinOrderArgs extends ReorderPinnedThreadRequest { + threadId: string; +} +interface ThreadQueuedMessageArgs { + signal?: AbortSignal; + threadId: string; +} +interface ThreadQueuedMessageCreateArgs extends CreateQueuedMessageRequest { + threadId: string; +} +interface ThreadQueuedMessageUpdateArgs extends ThreadQueuedMessageTargetArgs, UpdateQueuedMessageRequest { +} +interface ThreadQueuedMessageTargetArgs { + queuedMessageId: string; + threadId: string; +} +interface ThreadQueuedMessageSendArgs extends ThreadQueuedMessageTargetArgs, SendQueuedMessageRequest { +} +interface ThreadQueuedMessageReorderArgs extends ThreadQueuedMessageTargetArgs, ReorderQueuedMessageRequest { +} +interface ThreadQueuedMessageGroupBoundaryArgs extends SetQueuedMessageGroupBoundaryRequest { + threadId: string; +} +interface ThreadStorageFilesArgs extends ThreadStorageFilesQuery { + signal?: AbortSignal; + threadId: string; +} +interface ThreadStoragePathsArgs extends ThreadStoragePathsQuery { + signal?: AbortSignal; + threadId: string; +} +interface ThreadTimelineTurnSummaryDetailsArgs extends TimelineTurnSummaryDetailsQuery { + signal?: AbortSignal; + threadId: string; +} +interface ThreadTabsUpdateArgs extends UpdateThreadTabsRequest { + threadId: string; +} +interface ThreadOpenArgs { + threadId: string; + split?: ThreadOpenSplit; + file: ThreadOpenFile | null; +} +interface ThreadPaneActionArgs { + action: ThreadPaneAction; + threadId: string; +} +interface ThreadEventsListArgs { + afterSeq?: string; + limit?: string; + signal?: AbortSignal; + threadId: string; +} +interface ThreadEventWaitArgs { + afterSeq?: string; + signal?: AbortSignal; + threadId: string; + type: string; + waitMs: string; +} +interface ThreadTimelineArgs extends ThreadTimelineQuery { + signal?: AbortSignal; + threadId: string; +} +interface ThreadOutputArgs { + signal?: AbortSignal; + threadId: string; +} +interface ThreadInteractionListArgs { + signal?: AbortSignal; + threadId: string; +} +interface ThreadInteractionTargetArgs { + interactionId: string; + threadId: string; +} +interface ThreadInteractionGetArgs extends ThreadInteractionTargetArgs { + signal?: AbortSignal; +} +interface ThreadInteractionResolveArgs extends ThreadInteractionTargetArgs { + resolution: PendingInteractionResolution; +} +interface ThreadInteractionRespondArgs extends ThreadInteractionTargetArgs { + value: JsonValue; +} +type ThreadWaitTarget = { + kind: "status"; + status: ThreadStatus; +} | { + kind: "event"; + eventType: string; +}; +interface ThreadWaitArgs { + event?: string; + pollIntervalMs?: number; + signal?: AbortSignal; + status?: ThreadStatus; + threadId: string; + timeoutMs?: number; +} +type ThreadWaitResult = { + event: NonNullable; + matched: true; + target: Extract; + threadId: string; +} | { + matched: true; + target: Extract; + thread: ThreadGetResult; + threadId: string; +}; +interface ThreadInteractionsArea { + cancel(args: ThreadInteractionTargetArgs): Promise; + get(args: ThreadInteractionGetArgs): Promise; + list(args: ThreadInteractionListArgs): Promise; + resolve(args: ThreadInteractionResolveArgs): Promise; + respond(args: ThreadInteractionRespondArgs): Promise; +} +interface ThreadEventsArea { + list(args: ThreadEventsListArgs): Promise; + wait(args: ThreadEventWaitArgs): Promise; +} +interface ThreadQueuedMessagesArea { + create(args: ThreadQueuedMessageCreateArgs): Promise; + delete(args: ThreadQueuedMessageTargetArgs): Promise; + list(args: ThreadQueuedMessageArgs): Promise; + reorder(args: ThreadQueuedMessageReorderArgs): Promise; + send(args: ThreadQueuedMessageSendArgs): Promise; + setGroupBoundary(args: ThreadQueuedMessageGroupBoundaryArgs): Promise; + update(args: ThreadQueuedMessageUpdateArgs): Promise; +} +interface ThreadTabsArea { + get(args: ThreadStatusArgs): Promise; + update(args: ThreadTabsUpdateArgs): Promise; +} +interface ThreadsArea { + archive(args: ThreadActionArgs): Promise; + archiveAll(args: ThreadActionArgs): Promise; + childSummary(args: ThreadStatusArgs): Promise; + cancelPlan(args: ThreadActionArgs): Promise; + clearGoal(args: ThreadActionArgs): Promise; + conversationOutline(args: ThreadStatusArgs): Promise; + defaultExecutionOptions(args: ThreadStatusArgs): Promise; + delete(args: ThreadDeleteArgs): Promise; + events: ThreadEventsArea; + fork(args: ThreadForkArgs): Promise; + get(args: ThreadGetArgs): Promise; + interactions: ThreadInteractionsArea; + list(args?: ThreadListArgs): Promise; + markRead(args: ThreadActionArgs): Promise; + markUnread(args: ThreadActionArgs): Promise; + open(args: ThreadOpenArgs): Promise; + paneAction(args: ThreadPaneActionArgs): Promise; + output(args: ThreadOutputArgs): Promise; + pin(args: ThreadActionArgs): Promise; + promptHistory(args: ThreadPromptHistoryArgs): Promise; + queuedMessages: ThreadQueuedMessagesArea; + reorderPinned(args: ThreadPinOrderArgs): Promise; + search(args: ThreadSearchArgs): Promise; + send(args: ThreadSendArgs): Promise; + spawn(args: ThreadSpawnArgs): Promise; + stop(args: ThreadActionArgs): Promise; + tabs: ThreadTabsArea; + timeline(args: ThreadTimelineArgs): Promise; + timelineTurnSummaryDetails(args: ThreadTimelineTurnSummaryDetailsArgs): Promise; + storageFiles(args: ThreadStorageFilesArgs): Promise; + storagePaths(args: ThreadStoragePathsArgs): Promise; + unarchive(args: ThreadActionArgs): Promise; + unpin(args: ThreadActionArgs): Promise; + update(args: ThreadUpdateArgs): Promise; + wait(args: ThreadWaitArgs): Promise; +} + +type ThreadSectionCreateResult = ThreadSectionResponse; +type ThreadSectionUpdateResult = ThreadSectionMutationResponse; +type ThreadSectionDeleteResult = ThreadSectionMutationResponse; +type ThreadSectionListResult = ThreadSectionResponse[]; +interface ThreadSectionListArgs { + signal?: AbortSignal; +} +interface ThreadSectionsArea { + create(args: CreateThreadSectionRequest): Promise; + delete(args: DeleteThreadSectionRequest): Promise; + list(args?: ThreadSectionListArgs): Promise; + update(args: UpdateThreadSectionRequest): Promise; +} + +interface BbSdk extends BbRealtime { + environments: EnvironmentsArea; + files: FilesArea; + guide: GuideArea; + hosts: HostsArea; + projects: ProjectsArea; + plugins: PluginsArea; + providers: ProvidersArea; + status: StatusArea; + system: SystemArea; + terminals: TerminalsArea; + theme: ThemeArea; + threadSections: ThreadSectionsArea; + threads: ThreadsArea; +} + +/** + * The backend plugin API contract — the `bb` object handed to a plugin's + * `server.ts` factory (`export default function plugin(bb: BbPluginApi)`). + * + * Types only: the implementation lives in the BB server + * (apps/server/src/services/plugins/plugin-api.ts), which imports these + * shapes so the contract and the implementation cannot drift. Plugin authors + * import them type-only (`import type { BbPluginApi } from + * "@bb/plugin-sdk"`); the import is erased when BB loads the file. + * + * Runtime classes stay host-side. NeedsConfigurationError in particular is + * matched by NAME, so plugin code needs no runtime import: + * `throw Object.assign(new Error(msg), { name: "NeedsConfigurationError" })`. + */ +interface PluginLogger { + debug(message: string): void; + info(message: string): void; + warn(message: string): void; + error(message: string): void; +} +/** + * Declarative settings descriptors (`bb.settings.define`). Deliberately plain + * data — not zod — so the host can render settings forms and the CLI can + * parse values without executing plugin code. + */ +type PluginSettingDescriptor = { + type: "string"; + label: string; + description?: string; + /** Stored in a 0600 file under /plugins//secrets/, never in the db or sent to the frontend. */ + secret?: true; + default?: string; +} | { + type: "boolean"; + label: string; + description?: string; + default?: boolean; +} | { + type: "select"; + label: string; + description?: string; + options: string[]; + default?: string; +} | { + type: "project"; + label: string; + description?: string; + default?: string; +}; +type PluginSettingDescriptors = Record; +type PluginSettingValue = string | boolean; +/** `default` present → non-optional value; absent → `T | undefined`. */ +type PluginSettingsValues> = { + [K in keyof Ds]: Ds[K] extends { + default: string | boolean; + } ? PluginSettingValueOf : PluginSettingValueOf | undefined; +}; +type PluginSettingValueOf = D extends { + type: "boolean"; +} ? boolean : string; +interface PluginSettingsHandle> { + /** Load-safe: callable inside the factory. */ + get(): Promise>; + /** Fires after values change through the settings route/CLI. */ + onChange(listener: (next: PluginSettingsValues, prev: PluginSettingsValues) => void): void; +} +interface PluginSettings { + define>(descriptors: Ds): PluginSettingsHandle; +} +interface PluginKvStorage { + get(key: string): Promise; + set(key: string, value: unknown): Promise; + delete(key: string): Promise; + list(prefix?: string): Promise; +} +interface PluginStorage { + /** Namespaced JSON key-value rows in bb.db; values ≤256KB each. */ + kv: PluginKvStorage; + /** + * Open (or reuse the path of) the plugin's own SQLite database at + * /plugins//data.db — the server's better-sqlite3, WAL mode, + * busy_timeout 5000. Handles are host-tracked and closed on + * dispose/reload; a closed handle throws on use. + */ + database(): Database.Database; + /** + * Ordered-statement migration helper: statement index = migration id in a + * `_bb_migrations` table; unapplied statements run in one transaction. + * Append-only — never reorder or edit shipped statements. + */ + migrate(db: Database.Database, statements: string[]): void; +} +/** + * Thread lifecycle events a plugin can observe (design §4.5). Observe-only: + * handlers run fire-and-forget after the transition is applied and can never + * block or veto it. `thread` is the same public DTO GET /threads/:id serves. + */ +interface PluginThreadEventPayloads { + /** Fired after a thread row is created. */ + "thread.created": { + thread: ThreadResponse; + }; + /** Fired when a thread transitions into `active`. */ + "thread.active": { + thread: ThreadResponse; + }; + /** Fired when a thread transitions into `idle`. `lastAssistantText` is + * assembled the same way GET /threads/:id/output is. */ + "thread.idle": { + thread: ThreadResponse; + lastAssistantText: string | null; + }; + /** Fired when a thread transitions into `error`. `error` is the latest + * system/error event message, when one exists. */ + "thread.failed": { + thread: ThreadResponse; + error: string | null; + }; + /** Fired after a thread is archived (including cascade archives). */ + "thread.archived": { + thread: ThreadResponse; + }; + /** Fired after a thread is soft-deleted. */ + "thread.deleted": { + thread: ThreadResponse; + }; +} +type PluginThreadEventName = keyof PluginThreadEventPayloads; +type PluginThreadEventHandler = (payload: PluginThreadEventPayloads[E]) => void | Promise; +type PluginHttpAuthMode = "local" | "token" | "none"; +type PluginHttpHandler = (context: Context) => Response | Promise; +interface PluginHttp { + /** + * Register an HTTP route, mounted at + * `/api/v1/plugins//http/`. Auth modes (default "local"): + * - "local": Origin/Host must be a local BB app origin; non-GET requires + * content-type application/json (forces a CORS preflight). + * - "token": requires the per-plugin token (`bb plugin token `) via + * the x-bb-plugin-token header or ?token=. + * - "none": no checks — only for signature-verified webhooks. + */ + route(method: string, path: string, handler: PluginHttpHandler, opts?: { + auth?: PluginHttpAuthMode; + }): void; +} +interface PluginRpc { + /** + * Register a Standard Schema-driven rpc contract and its inferred handlers, + * served at POST + * `/api/v1/plugins//rpc/` with "local" auth semantics. The + * host validates input before invocation and output before strict JSON + * serialization. The response is `{ ok: true, result }` or + * `{ ok: false, error: { code, message, issues? } }`. + */ + register(contract: Contract, handlers: PluginRpcHandlers): void; +} +interface PluginRealtime { + /** + * Broadcast an ephemeral `plugin-signal` WS message + * `{ pluginId, channel, payload }` to every connected client (V1 has no + * per-channel subscriptions). `payload` must be JSON-serializable; + * `undefined` is normalized to `null`. Nothing is persisted. + */ + publish(channel: string, payload: unknown): void; +} +interface PluginBackground { + /** + * Register a long-lived background service. `start` runs after the + * factory completes and should resolve when `signal` aborts + * (dispose/reload/disable/shutdown). A crash restarts it with capped + * exponential backoff; throwing NeedsConfigurationError marks the plugin + * `needs-configuration` and stops restarting until the next load. + */ + service(name: string, service: { + start(signal: AbortSignal): void | Promise; + }): void; + /** + * Register a cron schedule (5-field expression, server-local time). The + * durable row keyed (pluginId, name) is upserted at load; the periodic + * sweep claims due rows with a CAS on next_run_at, but only while this + * plugin is loaded. Failures land in last_status/last_error, visible in + * `bb plugin list`. + */ + schedule(name: string, cron: string, fn: () => void | Promise): void; +} +interface PluginCliCommandInfo { + name: string; + summary: string; + usage: string; +} +/** Context forwarded from the invoking CLI when known; all fields optional. */ +interface PluginCliContext { + cwd?: string; + threadId?: string; + projectId?: string; + /** Aborted when the invoking CLI HTTP request disconnects. */ + signal?: AbortSignal; +} +type PluginInteractionCancelReason = "user" | "request-aborted" | "thread-stopped" | "thread-deleted" | "plugin-disposed" | "server-restarted" | "timeout"; +type PluginInteractionResult = { + outcome: "submitted"; + value: JsonValue$1; +} | { + outcome: "cancelled"; + reason: PluginInteractionCancelReason; +}; +interface PluginInteractionRequest { + threadId: string; + rendererId: string; + title: string; + payload: JsonValue$1; + /** Defaults to ten minutes; capped at one hour. */ + timeoutMs?: number; +} +interface PluginCliResult { + exitCode: number; + stdout?: string; + stderr?: string; +} +/** + * Maximum combined UTF-8 bytes accepted from plugin CLI stdout and stderr. + * This is the shared source of truth for production and the testing harness. + */ +declare const PLUGIN_CLI_OUTPUT_MAX_BYTES: number; +interface PluginCliOutputLimitError { + code: "plugin_cli_output_too_large"; + message: string; + maxBytes: number; + stdoutBytes: number; + stderrBytes: number; + totalBytes: number; +} +/** Normalized host result returned by the plugin CLI HTTP/testing boundary. */ +interface PluginCliExecutionResult { + exitCode: number; + stdout: string; + stderr: string; + error?: PluginCliOutputLimitError; +} +interface PluginCliRegistration { + /** Top-level command name (`bb …`): lowercase [a-z0-9-]+, and not + * a core bb command (see RESERVED_BB_CLI_COMMANDS in the server). */ + name: string; + summary: string; + /** Subcommand metadata rendered in help and the plugin-commands skill + * without executing plugin code. Parsing argv is plugin-owned. */ + commands?: PluginCliCommandInfo[]; + run(argv: string[], ctx: PluginCliContext): PluginCliResult | Promise; +} +interface PluginCli { + /** + * Register this plugin's `bb` subcommand. One registration per factory + * execution; a repeated call is rejected. Core bb commands always win + * name collisions; reserved names are rejected at registration. + */ + register(registration: PluginCliRegistration): void; +} +/** Per-turn context handed to bb.agents context providers (design §4.4). */ +/** MCP-style content parts a native tool may return (design §4.4). */ +type PluginAgentToolContentPart = { + type: "text"; + text: string; +} | { + type: "image"; + data: string; + mimeType: string; +}; +type PluginAgentToolResult = string | { + content: PluginAgentToolContentPart[]; + isError?: boolean; +}; +/** Per-call context handed to a native tool's execute (design §4.4). */ +interface PluginAgentToolContext { + threadId: string; + projectId: string; + /** The tool-call request's abort signal (aborts if the daemon round-trip + * is torn down mid-call). */ + signal: AbortSignal; +} +interface PluginAgentToolRegistrationBase { + /** Tool name shown to the model: [a-zA-Z0-9_-]+, unique across plugins, + * and not a built-in dynamic tool (see RESERVED_AGENT_TOOL_NAMES in the + * server). */ + name: string; + description: string; + /** + * Optional usage snippet appended to the thread instructions whenever + * this tool is in the session's tool set (mirrors the built-in + * update_environment_directory guidance). Limited to 4096 characters. + */ + instructions?: string; +} +/** Stable, plain-data context resolved by the server for one agent session. */ +interface PluginAgentConfigurationContext { + thread: { + id: string; + title: string | null; + parentThreadId: string | null; + sourceThreadId: string | null; + }; + project: { + id: string; + kind: "standard" | "personal"; + name: string; + gitRemoteUrl: string | null; + }; + environment: { + id: string; + name: string | null; + path: string | null; + workspaceProvisionType: "unmanaged" | "managed-worktree" | "personal"; + branchName: string | null; + }; + host: { + id: string; + name: string; + }; + provider: { + id: string; + model: string; + }; + sideChat: boolean; + origin: { + kind: "fork" | "side-chat" | null; + pluginId: string | null; + }; +} +/** Object form of a {@link PluginAgentConfiguration} tools entry: selects a + * registered tool and overrides the parameter schema advertised to the + * provider for this resolution only. */ +interface PluginAgentToolSelection { + /** Name of a tool registered by this plugin via `registerTool`. */ + name: string; + /** JSON-schema object (root `type: "object"`, JSON-serializable, at most + * 128 KiB serialized) sent to the provider in place of the registered + * parameter schema. Execution-side validation still runs the registered + * parameters, so the override must only narrow what the registered schema + * already accepts. */ + parameters: Record; +} +/** Per-resolution selection returned by {@link PluginAgents.configure}. */ +interface PluginAgentConfiguration { + /** Tool names registered by this plugin, or {@link PluginAgentToolSelection} + * entries to also override a tool's advertised parameter schema for this + * resolution. Duplicate or unknown names, or an invalid override, reject + * this plugin's complete selection for the resolution. */ + tools: Array; + /** Skill frontmatter names from this plugin's manifest skill roots. + * Duplicate or unknown names reject this plugin's complete selection. */ + skills: string[]; + /** Optional dynamic instructions. Output is truncated to 4096 characters. */ + instructions?: string; +} +interface PluginAgents { + /** + * Select this plugin's statically registered tools and manifest skills for + * each thread/session resolution, with optional dynamic instructions. The + * callback is synchronous and runs at `thread.start` / `turn.submit`; it + * never rebuilds registrations. Exactly one callback may be registered per + * factory execution. A throw, malformed result, duplicate id, unknown id, + * or more than 256 tool/skill ids fails closed for this plugin only. + * + * Tools take effect when the provider session is next started or resumed; + * an already-running session is not hot-mutated. Instructions are resolved + * for the next turn. Skill changes follow BB's environment runtime policy: + * a busy runtime keeps its current catalog until a safe relaunch. Side-chat + * threads receive `sideChat: true`, and their returned tool, skill, and + * dynamic-instruction selections apply at the same boundaries. Independent + * side-chat safety policy (such as permission escalation) is unchanged. + */ + configure(provider: (context: PluginAgentConfigurationContext) => PluginAgentConfiguration): void; + /** + * Register a native dynamic tool (design §4.4). `parameters` is either a + * zod schema (validated per call; execute receives the parsed value) or a + * plain JSON-schema object (no validation; execute receives the raw + * arguments as `unknown`). Tool-set changes apply on the NEXT session + * start — a tool registered mid-session is not hot-added to running + * provider sessions. A second registration of the same name within this + * plugin is rejected; a name already registered by another plugin is + * rejected and surfaced as this plugin's status detail. + */ + registerTool(tool: PluginAgentToolRegistrationBase & { + parameters: Schema; + execute(params: z.output, ctx: PluginAgentToolContext): PluginAgentToolResult | Promise; + }): void; + registerTool(tool: PluginAgentToolRegistrationBase & { + /** Raw JSON-schema escape hatch; params arrive unvalidated. */ + parameters: Record; + execute(params: unknown, ctx: PluginAgentToolContext): PluginAgentToolResult | Promise; + }): void; + /** + * Contribute a dynamic section appended to thread instructions. The + * provider runs when a thread's runtime command config is resolved + * (thread.start / turn.submit); return null to contribute nothing for + * that resolution. Must be synchronous and fast — it sits on the + * thread-start path. Output longer than 4096 characters is truncated; a + * throwing provider is logged against the plugin and contributes nothing. + * A repeated registration within one factory execution is rejected. + * This legacy contribution is not applied to side-chat threads; use + * configure() when sideChat-aware dynamic instructions are required. + */ + contributeInstructions(provider: (ctx: { + threadId: string; + projectId: string; + }) => string | null): void; +} +interface PluginThreadActionContext { + threadId: string; + projectId: string; +} +interface PluginThreadActionToast { + kind: "success" | "error" | "info"; + message: string; +} +type PluginThreadActionResult = void | { + toast?: PluginThreadActionToast; +}; +interface PluginThreadActionRegistration { + /** Unique within this plugin: [a-zA-Z0-9_-]+ (becomes a URL segment). */ + id: string; + /** Button label rendered in the thread header. */ + title: string; + /** Optional icon name; the host falls back to a generic icon. */ + icon?: string; + /** Optional confirmation prompt the host shows before running. */ + confirm?: string; + /** + * Runs server-side when the user clicks the action. The host shows a + * pending state while in flight, the returned toast on completion, and an + * automatic error toast when this throws. + */ + run(ctx: PluginThreadActionContext): PluginThreadActionResult | Promise; +} +type PluginMentionTrigger = "@" | "#" | "$" | "!" | "~"; +/** Search context handed to a mention provider (design §4.9). `projectId`/ + * `threadId` are null when the composer has not committed one yet. */ +interface PluginMentionSearchContext { + trigger: PluginMentionTrigger; + query: string; + projectId: string | null; + threadId: string | null; +} +/** One row a mention provider returns from `search`. `id` is the provider's + * own item id — the host namespaces it before it reaches the wire. */ +interface PluginMentionItem { + id: string; + title: string; + subtitle?: string; + icon?: string; +} +interface PluginMentionProviderRegistration { + /** Unique within this plugin: [a-zA-Z0-9_-]+ (no ":" — the host composes + * wire item ids as ":"). */ + id: string; + /** Section label shown above this provider's rows in the mention menu. */ + label: string; + /** + * Composer trigger characters this provider should answer. Omit to use the + * default `@` mention trigger. Valid triggers are `@`, `#`, `$`, `!`, and `~`. + */ + triggers?: readonly PluginMentionTrigger[]; + /** + * Runs server-side as the user types after one of this provider's triggers + * in the composer. Each call is time-boxed (2s) and failure-isolated: a slow + * or throwing provider contributes an empty list — it can never break the + * mention menu. + */ + search(ctx: PluginMentionSearchContext): PluginMentionItem[] | Promise; + /** + * Resolves one picked item into agent context, called once per unique + * item at message send time. The returned `context` is attached to the + * message as an agent-visible (user-hidden) prompt input. Throwing blocks + * the send with a visible error. + */ + resolve(itemId: string): { + context: string; + } | Promise<{ + context: string; + }>; +} +interface PluginUi { + /** Block until the app submits or cancels a plugin-owned composer form. */ + requestInput(request: PluginInteractionRequest, options?: { + signal?: AbortSignal; + }): Promise; + /** + * Register a thread action rendered in the shipped app's thread header + * (design §4.9). Multiple actions per plugin; ids must be unique within + * the plugin. Invoked via POST /plugins/:id/actions/:actionId. + */ + registerThreadAction(action: PluginThreadActionRegistration): void; + /** + * Register a mention provider for the shipped app's composer (design §4.9). + * Providers default to the `@` trigger and may opt into `#`, `$`, `!`, or + * `~` with `triggers`. Items group under `label` in the mention menu; a + * picked item becomes a `{ kind: "plugin" }` mention resource whose context + * is resolved once at send time. Multiple providers per plugin; ids must be + * unique within the plugin. + */ + registerMentionProvider(provider: PluginMentionProviderRegistration): void; +} +interface PluginEvents { + /** + * Add a thread lifecycle listener. Multiple listeners for the same event are + * additive and run independently in registration order. + */ + on(event: E, handler: PluginThreadEventHandler): void; +} +interface PluginServerApi { + /** + * This BB server's own loopback base URL (e.g. "http://127.0.0.1:38886"), + * which serves the SPA + /api + /ws. For plugins that proxy or relay + * traffic back to the server itself (e.g. a tunnel). Bind-gated like + * `bb.sdk`: reading it before the server is listening throws, so prefer + * reading it from handlers, services, and timers. + */ + readonly loopbackBaseUrl: string; +} +interface PluginSharedPortTunnelIdentity { + /** Gate routing label assigned to this machine. */ + label: string; + /** Gate apex without a scheme, e.g. "getbb.app". */ + baseDomain: string; +} +interface PluginHosts { + /** + * Ensure this enrolled host has a gate label and return its read-only public + * identity. The daemon chooses the trusted gate and desired label; plugins + * cannot influence either credential-bearing destination. + */ + ensureSharedPortTunnel(hostId: string): Promise; + /** + * Replace this plugin's desired shared-loopback ports for one host. The + * server aggregates declarations, owns generations, and delivers the + * resulting set to that host's daemon. Tunnel identity is deliberately not + * accepted here: it is owned by the daemon's trusted enrollment. + */ + declareSharedPorts(hostId: string, ports: readonly number[]): void; +} +interface PluginStatusApi { + /** + * Mark this plugin `needs-configuration` (with a message shown in + * `bb plugin list` and the UI) instead of failing — e.g. a factory or + * service that finds no API key configured. Cleared on the next load; + * saving settings does not auto-reload in V1, so ask the user to + * `bb plugin reload ` after configuring. + */ + needsConfiguration(message: string): void; +} +/** + * The API object handed to a plugin's factory (design §4). Implemented by + * the BB server; this contract is what plugin `server.ts` files compile + * against. + */ +interface BbPluginApi { + /** The plugin's own id (namespaces storage, routes, commands). */ + readonly pluginId: string; + /** Leveled, plugin-scoped logger. */ + readonly log: PluginLogger; + /** Declarative settings (design §4.2). */ + readonly settings: PluginSettings; + /** Namespaced KV + per-plugin database (design §4.3). */ + readonly storage: PluginStorage; + /** HTTP routes under /api/v1/plugins//http/* (design §4.6). */ + readonly http: PluginHttp; + /** RPC methods under /api/v1/plugins//rpc/ (design §4.6). */ + readonly rpc: PluginRpc; + /** Ephemeral push to connected frontends (design §4.7). */ + readonly realtime: PluginRealtime; + /** Long-lived services + cron schedules (design §4.8). */ + readonly background: PluginBackground; + /** Agent-facing `bb` CLI subcommand (design §4.4). */ + readonly cli: PluginCli; + /** Per-turn agent context contributions (design §4.4). */ + readonly agents: PluginAgents; + /** Host-rendered UI contributions (design §4.9). */ + readonly ui: PluginUi; + /** Additive plugin lifecycle listeners (design §4.5). */ + readonly events: PluginEvents; + /** Plugin-reported status (needs-configuration). */ + readonly status: PluginStatusApi; + /** Read-only facts about the running server (loopback base URL). */ + readonly server: PluginServerApi; + /** Server-to-daemon host control-plane declarations. */ + readonly hosts: PluginHosts; + /** + * The full BB SDK, bound to this server over loopback (design §4.1). + * Bind-gated: reading this before the host binds the SDK throws. The real + * server binds it before loading plugins, so it is available from the + * moment factories run there — but isolated harnesses may not, so prefer + * using it from handlers, services, and timers for portability. + * `threads.spawn` defaults `origin` to "plugin" and `originPluginId` to + * this plugin's id so spawned threads are attributed automatically. + */ + readonly sdk: BbSdk; + /** + * Register cleanup to run on reload/disable/shutdown. Hooks run LIFO. + * The sanctioned place to clear timers and close connections. + */ + onDispose(hook: () => void | Promise): void; +} + +export { PLUGIN_CLI_OUTPUT_MAX_BYTES, defineRpcContract }; +export type { BbContext, BbNavigate, BbPluginApi, ComposerCustomization, ComposerPlusMenuItem, ComposerRichTextSpec, ComposerStructuredDraft, ComposerView, JsonValue$1 as JsonValue, MarkdownProps, PluginAgentConfiguration, PluginAgentConfigurationContext, PluginAgentToolContentPart, PluginAgentToolContext, PluginAgentToolRegistrationBase, PluginAgentToolResult, PluginAgentToolSelection, PluginAgents, PluginAppBuilder, PluginAppComposer, PluginAppContentScripts, PluginAppDefinition, PluginAppSetup, PluginAppSlots, PluginBackground, PluginCli, PluginCliCommandInfo, PluginCliContext, PluginCliExecutionResult, PluginCliOutputLimitError, PluginCliRegistration, PluginCliResult, PluginComposerApi, PluginComposerMention, PluginComposerScope, PluginComposerTextEffect, PluginComposerThreadRowStatus, PluginContentScriptContext, PluginContentScriptDisposer, PluginContentScriptRegistration, PluginEvents, PluginFileOpenerProps, PluginFileOpenerRegistration, PluginFileOpenerSource, PluginHomepageSectionProps, PluginHomepageSectionRegistration, PluginHosts, PluginHttp, PluginHttpAuthMode, PluginHttpHandler, PluginInteractionCancelReason, PluginInteractionRequest, PluginInteractionResult, PluginKvStorage, PluginLogger, PluginMentionItem, PluginMentionProviderRegistration, PluginMentionSearchContext, PluginMentionTrigger, PluginMessageActionContext, PluginMessageActionRegistration, PluginMessageActionThreadPanelOptions, PluginMessageDirectiveMessage, PluginMessageDirectiveOpenWorkspaceFile, PluginMessageDirectiveProps, PluginMessageDirectiveRegistration, PluginNavPanelProps, PluginNavPanelRegistration, PluginPendingInteractionProps, PluginPendingInteractionRegistration, PluginPendingInteractionView, PluginRealtime, PluginRealtimeConnectionState, PluginRpc, PluginRpcCallArgs, PluginRpcClient, PluginRpcContract, PluginRpcError, PluginRpcErrorCode, PluginRpcHandlers, PluginRpcIssuePathSegment, PluginRpcMethodContract, PluginRpcResult, PluginRpcValidationIssue, PluginSdkApp, PluginServerApi, PluginSettingDescriptor, PluginSettingDescriptors, PluginSettingValue, PluginSettings, PluginSettingsHandle, PluginSettingsSectionProps, PluginSettingsSectionRegistration, PluginSettingsState, PluginSettingsValues, PluginSharedPortTunnelIdentity, PluginSidebarFooterActionContext, PluginSidebarFooterActionProps, PluginSidebarFooterActionRegistration, PluginStatusApi, PluginStorage, PluginThreadActionContext, PluginThreadActionRegistration, PluginThreadActionResult, PluginThreadActionToast, PluginThreadEventHandler, PluginThreadEventName, PluginThreadEventPayloads, PluginThreadPanelActionContext, PluginThreadPanelActionRegistration, PluginThreadPanelProps, PluginUi, StandardSchemaV1, StandardSchemaV1InferInput, StandardSchemaV1InferOutput, StandardSchemaV1Issue, StandardSchemaV1Result, ThreadChatMessageAction, ThreadChatMessageReference, ThreadChatProps }; From 4cb0fa6aed8a482c434822a64efcdc56b53a513a Mon Sep 17 00:00:00 2001 From: Bersabel Tadesse Date: Thu, 23 Jul 2026 01:34:43 -0700 Subject: [PATCH 2/4] Handle personal projects in thread organizer --- plugins/thread-organizer/server.test.ts | 23 +++++++++++++++++++++++ plugins/thread-organizer/server.ts | 14 ++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/plugins/thread-organizer/server.test.ts b/plugins/thread-organizer/server.test.ts index b8c9f89..c4296cc 100644 --- a/plugins/thread-organizer/server.test.ts +++ b/plugins/thread-organizer/server.test.ts @@ -154,6 +154,29 @@ describe("Thread Organizer plugin", () => { await harness.lifecycle.dispose(); }); + it("classifies personal-workspace threads without a project GET", async () => { + const { bb, harness, currentThread } = createHarness({ + thread: { projectId: "proj_personal" }, + }); + plugin(bb); + + await harness.behavior.emitThreadEvent("thread.created", { + thread: currentThread(), + }); + + expect( + harness.inspection.sdk.callsTo("projects.get"), + ).toHaveLength(0); + expect(harness.inspection.logEntries).toContainEqual( + expect.objectContaining({ + message: expect.stringContaining( + "mode=observe action=propose-section target=extensions", + ), + }), + ); + await harness.lifecycle.dispose(); + }); + it("places a new unsectioned plugin thread in Extensions in apply mode", async () => { const { bb, harness, currentThread, update } = createHarness({ mode: "apply", diff --git a/plugins/thread-organizer/server.ts b/plugins/thread-organizer/server.ts index c96ff98..12005cd 100644 --- a/plugins/thread-organizer/server.ts +++ b/plugins/thread-organizer/server.ts @@ -11,6 +11,7 @@ import { } from "./core.js"; const STATE_PREFIX = "thread:v1:"; +const PERSONAL_PROJECT_ID = "proj_personal"; const NEW_SECTION_CONFIDENCE = 0.85; const NEW_SECTION_MARGIN = 0.2; const MOVE_SECTION_CONFIDENCE = 0.92; @@ -353,11 +354,16 @@ export default function plugin(bb: BbPluginApi): void { if (!state.sectionLocked) { try { - const project = await bb.sdk.projects.get({ - projectId: thread.projectId, - }); + const projectName = + thread.projectId === PERSONAL_PROJECT_ID + ? "Personal" + : ( + await bb.sdk.projects.get({ + projectId: thread.projectId, + }) + ).name; const decision = classifySection({ - projectName: project.name, + projectName, texts, }); if (decision !== null) { From 517cc53f70a39832589b6c9ae5fe08f7833ee0b9 Mon Sep 17 00:00:00 2001 From: Bersabel Tadesse Date: Thu, 23 Jul 2026 01:57:13 -0700 Subject: [PATCH 3/4] Fix periodic thread reorganization --- plugins/thread-organizer/server.test.ts | 96 ++++++++++++++++++++++++- plugins/thread-organizer/server.ts | 19 ++++- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/plugins/thread-organizer/server.test.ts b/plugins/thread-organizer/server.test.ts index c4296cc..46daf4c 100644 --- a/plugins/thread-organizer/server.test.ts +++ b/plugins/thread-organizer/server.test.ts @@ -52,6 +52,7 @@ function createHarness(input?: { ...input?.thread, }); const events: ReturnType[] = []; + let promptHistory = [promptEntry(prompt)]; const update = vi.fn( async (args: { sectionId?: string | null; @@ -90,7 +91,7 @@ function createHarness(input?: { }, }, get: async () => thread, - promptHistory: async () => [promptEntry(prompt)], + promptHistory: async () => promptHistory, update, }, }, @@ -105,6 +106,11 @@ function createHarness(input?: { currentThread() { return thread; }, + setPromptHistory(...texts: string[]): void { + promptHistory = texts.map((text, index) => + promptEntry(text, index + 1), + ); + }, setThread( changes: Partial>, ): void { @@ -292,6 +298,94 @@ describe("Thread Organizer plugin", () => { await organizer.harness.lifecycle.dispose(); }); + it("moves a managed section after two due evaluations of clear recent intent", async () => { + const initialPrompt = "Write a blog post about organizing bb threads."; + const organizer = createHarness({ + mode: "apply", + projectName: "Personal", + prompt: initialPrompt, + thread: { + projectId: "proj_personal", + title: "Write Thread Organization Blog Post", + }, + }); + plugin(organizer.bb); + await organizer.harness.behavior.emitThreadEvent("thread.created", { + thread: organizer.currentThread(), + }); + expect(organizer.currentThread().sectionId).toBe("sec_writing"); + + organizer.setPromptHistory( + initialPrompt, + "Create a bb plugin for automatic thread organization.", + ); + organizer.addCompletedTurn(10); + await organizer.harness.behavior.emitThreadEvent("thread.idle", { + lastAssistantText: "Done.", + thread: organizer.currentThread(), + }); + expect(organizer.currentThread().sectionId).toBe("sec_writing"); + + for (let turn = 2; turn <= 5; turn += 1) { + organizer.addCompletedTurn(turn * 10); + await organizer.harness.behavior.emitThreadEvent("thread.idle", { + lastAssistantText: "Done.", + thread: organizer.currentThread(), + }); + } + + expect(organizer.currentThread().sectionId).toBe("sec_extensions"); + expect( + organizer.update.mock.calls.filter( + ([args]) => args.sectionId !== undefined, + ), + ).toEqual([ + [{ threadId: "thr_test", sectionId: "sec_writing" }], + [{ threadId: "thr_test", sectionId: "sec_extensions" }], + ]); + await organizer.harness.lifecycle.dispose(); + }); + + it("abstains from moving on mixed recent section intent", async () => { + const initialPrompt = "Write a blog post about organizing bb threads."; + const organizer = createHarness({ + mode: "apply", + projectName: "Personal", + prompt: initialPrompt, + }); + plugin(organizer.bb); + await organizer.harness.behavior.emitThreadEvent("thread.created", { + thread: organizer.currentThread(), + }); + + organizer.setPromptHistory( + initialPrompt, + "Write a blog post about creating a bb plugin.", + ); + organizer.addCompletedTurn(10); + await organizer.harness.behavior.emitThreadEvent("thread.idle", { + lastAssistantText: "Done.", + thread: organizer.currentThread(), + }); + for (let turn = 2; turn <= 5; turn += 1) { + organizer.addCompletedTurn(turn * 10); + await organizer.harness.behavior.emitThreadEvent("thread.idle", { + lastAssistantText: "Done.", + thread: organizer.currentThread(), + }); + } + + expect(organizer.currentThread().sectionId).toBe("sec_writing"); + expect( + organizer.update.mock.calls.filter( + ([args]) => args.sectionId !== undefined, + ), + ).toEqual([ + [{ threadId: "thr_test", sectionId: "sec_writing" }], + ]); + await organizer.harness.lifecycle.dispose(); + }); + it("ignores hidden and plugin-originated workers", async () => { const organizer = createHarness({ mode: "apply", diff --git a/plugins/thread-organizer/server.ts b/plugins/thread-organizer/server.ts index 12005cd..702202d 100644 --- a/plugins/thread-organizer/server.ts +++ b/plugins/thread-organizer/server.ts @@ -124,6 +124,14 @@ function promptTexts( ); } +function mostRecentSubstantiveText(texts: string[]): string | null { + for (let index = texts.length - 1; index >= 0; index -= 1) { + const text = texts[index]!; + if (isSubstantiveText(text)) return text; + } + return null; +} + function classificationSummary(decision: SectionClassification): string { return [ `target=${decision.target}`, @@ -350,6 +358,15 @@ export default function plugin(bb: BbPluginApi): void { ...(thread.titleFallback === null ? [] : [thread.titleFallback]), ...historyTexts, ]; + const latestPromptText = mostRecentSubstantiveText(historyTexts); + const sectionTexts = + phase === "turn" && + state.hasAppliedSection && + thread.sectionId !== null + ? latestPromptText === null + ? [] + : [latestPromptText] + : texts; const { mode } = await settings.get(); if (!state.sectionLocked) { @@ -364,7 +381,7 @@ export default function plugin(bb: BbPluginApi): void { ).name; const decision = classifySection({ projectName, - texts, + texts: sectionTexts, }); if (decision !== null) { const sectionId = resolveSectionId( From 1ee8746ba804613b1d5b8889c7daf9618bdac85d Mon Sep 17 00:00:00 2001 From: Bersabel Tadesse Date: Thu, 23 Jul 2026 02:34:39 -0700 Subject: [PATCH 4/4] Preserve periodic move confirmations --- plugins/thread-organizer/server.test.ts | 76 +++++++++++++++++++++++++ plugins/thread-organizer/server.ts | 14 ++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/plugins/thread-organizer/server.test.ts b/plugins/thread-organizer/server.test.ts index 46daf4c..786edf0 100644 --- a/plugins/thread-organizer/server.test.ts +++ b/plugins/thread-organizer/server.test.ts @@ -319,6 +319,10 @@ describe("Thread Organizer plugin", () => { initialPrompt, "Create a bb plugin for automatic thread organization.", ); + organizer.setThread({ status: "active" }); + await organizer.harness.behavior.emitThreadEvent("thread.active", { + thread: organizer.currentThread(), + }); organizer.addCompletedTurn(10); await organizer.harness.behavior.emitThreadEvent("thread.idle", { lastAssistantText: "Done.", @@ -327,6 +331,10 @@ describe("Thread Organizer plugin", () => { expect(organizer.currentThread().sectionId).toBe("sec_writing"); for (let turn = 2; turn <= 5; turn += 1) { + organizer.setThread({ status: "active" }); + await organizer.harness.behavior.emitThreadEvent("thread.active", { + thread: organizer.currentThread(), + }); organizer.addCompletedTurn(turn * 10); await organizer.harness.behavior.emitThreadEvent("thread.idle", { lastAssistantText: "Done.", @@ -386,6 +394,74 @@ describe("Thread Organizer plugin", () => { await organizer.harness.lifecycle.dispose(); }); + it("preserves a pending move across an unclassifiable active phase", async () => { + const organizer = createHarness({ + mode: "apply", + projectName: "Personal", + prompt: "Plan quarterly work.", + thread: { + projectId: "proj_personal", + title: "Quarterly Plan", + }, + }); + plugin(organizer.bb); + await organizer.harness.behavior.emitThreadEvent("thread.created", { + thread: organizer.currentThread(), + }); + expect(organizer.currentThread().sectionId).toBeNull(); + + organizer.setPromptHistory( + "Create a bb plugin for automatic thread organization.", + ); + organizer.setThread({ status: "active" }); + await organizer.harness.behavior.emitThreadEvent("thread.active", { + thread: organizer.currentThread(), + }); + expect(organizer.currentThread().sectionId).toBe("sec_extensions"); + + organizer.addCompletedTurn(10); + await organizer.harness.behavior.emitThreadEvent("thread.idle", { + lastAssistantText: "Done.", + thread: organizer.currentThread(), + }); + + organizer.setPromptHistory("Write a blog post about bb workflows."); + for (let turn = 2; turn <= 5; turn += 1) { + organizer.setThread({ status: "active" }); + await organizer.harness.behavior.emitThreadEvent("thread.active", { + thread: organizer.currentThread(), + }); + organizer.addCompletedTurn(turn * 10); + await organizer.harness.behavior.emitThreadEvent("thread.idle", { + lastAssistantText: "Done.", + thread: organizer.currentThread(), + }); + } + expect(organizer.currentThread().sectionId).toBe("sec_extensions"); + + organizer.setPromptHistory("ok"); + organizer.setThread({ status: "active" }); + await organizer.harness.behavior.emitThreadEvent("thread.active", { + thread: organizer.currentThread(), + }); + + organizer.setPromptHistory("Write a blog post about bb workflows."); + for (let turn = 6; turn <= 15; turn += 1) { + organizer.setThread({ status: "active" }); + await organizer.harness.behavior.emitThreadEvent("thread.active", { + thread: organizer.currentThread(), + }); + organizer.addCompletedTurn(turn * 10); + await organizer.harness.behavior.emitThreadEvent("thread.idle", { + lastAssistantText: "Done.", + thread: organizer.currentThread(), + }); + } + + expect(organizer.currentThread().sectionId).toBe("sec_writing"); + await organizer.harness.lifecycle.dispose(); + }); + it("ignores hidden and plugin-originated workers", async () => { const organizer = createHarness({ mode: "apply", diff --git a/plugins/thread-organizer/server.ts b/plugins/thread-organizer/server.ts index 702202d..407322a 100644 --- a/plugins/thread-organizer/server.ts +++ b/plugins/thread-organizer/server.ts @@ -228,6 +228,12 @@ export default function plugin(bb: BbPluginApi): void { if (state.sectionLocked) return; const movingManagedSection = thread.sectionId !== null; + if ( + movingManagedSection && + (!state.hasAppliedSection || phase !== "turn") + ) { + return; + } const minimumConfidence = movingManagedSection ? MOVE_SECTION_CONFIDENCE : NEW_SECTION_CONFIDENCE; @@ -249,7 +255,6 @@ export default function plugin(bb: BbPluginApi): void { } if (movingManagedSection) { - if (!state.hasAppliedSection || phase !== "turn") return; if (state.pendingSectionId === targetSectionId) { state.pendingSectionStreak += 1; } else { @@ -368,8 +373,13 @@ export default function plugin(bb: BbPluginApi): void { : [latestPromptText] : texts; const { mode } = await settings.get(); + const movingManagedSection = + state.hasAppliedSection && thread.sectionId !== null; - if (!state.sectionLocked) { + if ( + !state.sectionLocked && + (!movingManagedSection || phase === "turn") + ) { try { const projectName = thread.projectId === PERSONAL_PROJECT_ID