From 26722ea2d465724c60da3fd69c4bce793af29dab Mon Sep 17 00:00:00 2001 From: Sawyer Hood Date: Sat, 18 Jul 2026 08:57:45 -0700 Subject: [PATCH 1/8] Multiplayer wave 0: claimed-identity contract, presence wire schemas, attribution columns Shared contracts and schema for multiplayer bb, landed serially so parallel workstreams build against fixed interfaces: - @bb/domain claimed-identity: x-bb-claimed-identity handshake header schema, handle normalization, and boundary encode/decode. Identity is claimed-only; admission gateways (connect gate / network) never assert identity. - @bb/domain change-kinds: typing client message plus thread-presence and presence-summary broadcasts (strict + lenient pairs). - @bb/db: collaborators table (handle-keyed) and nullable attribution columns events.actor_handle, threads.created_by_handle, queued_thread_messages.actor_handle, pending_interactions.resolved_by_handle. Plain text columns without FKs so the migration stays ADD COLUMN only. - @bb/connect-db: server_member table (gate admission list, owner-managed). - Server: accept the typing message as a no-op until presence lands; migrate drift manifest and rewind/replay tests updated for migration 0079. Co-Authored-By: Claude Fable 5 --- apps/server/src/ws/client-protocol.ts | 5 + .../threads/thread-runtime-display.test.ts | 1 + .../migrations/0006_server-member.sql | 12 + .../migrations/meta/0006_snapshot.json | 960 +++++ .../connect-db/migrations/meta/_journal.json | 7 + packages/connect-db/src/schema.ts | 29 + .../0079_multiplayer-collaborators.sql | 12 + packages/db/drizzle/meta/0079_snapshot.json | 3453 +++++++++++++++++ packages/db/drizzle/meta/_journal.json | 7 + packages/db/src/migrate.ts | 6 + packages/db/src/schema.ts | 30 + packages/db/test/migrate.test.ts | 71 +- packages/db/test/schema.test.ts | 8 +- packages/domain/src/change-kinds.ts | 75 + packages/domain/src/claimed-identity.ts | 67 + packages/domain/src/index.ts | 1 + 16 files changed, 4733 insertions(+), 11 deletions(-) create mode 100644 packages/connect-db/migrations/0006_server-member.sql create mode 100644 packages/connect-db/migrations/meta/0006_snapshot.json create mode 100644 packages/db/drizzle/0079_multiplayer-collaborators.sql create mode 100644 packages/db/drizzle/meta/0079_snapshot.json create mode 100644 packages/domain/src/claimed-identity.ts diff --git a/apps/server/src/ws/client-protocol.ts b/apps/server/src/ws/client-protocol.ts index 943b3ee4c7..dd110d068d 100644 --- a/apps/server/src/ws/client-protocol.ts +++ b/apps/server/src/ws/client-protocol.ts @@ -50,6 +50,11 @@ export function onClientSocketMessage( deps.hub.unsubscribe(socket, parsed.target); deps.watchInterests.unsubscribe(socket, parsed.target); break; + case "typing": + // Presence typing signal; folded into presence state by the hub once + // multiplayer presence lands. Accepted (not an error) so newer clients + // never get their socket closed by an older server mid-rollout. + break; default: { const _exhaustive: never = parsed; throw new Error(`Unhandled client message: ${_exhaustive}`); diff --git a/apps/server/test/services/threads/thread-runtime-display.test.ts b/apps/server/test/services/threads/thread-runtime-display.test.ts index ab7b95de21..dfb771f734 100644 --- a/apps/server/test/services/threads/thread-runtime-display.test.ts +++ b/apps/server/test/services/threads/thread-runtime-display.test.ts @@ -204,6 +204,7 @@ function createThreadListEntry( ): ThreadWithPendingInteractionState { return { ...args.thread, + createdByHandle: null, modelOverride: null, reasoningLevelOverride: null, environmentBranchName: null, diff --git a/packages/connect-db/migrations/0006_server-member.sql b/packages/connect-db/migrations/0006_server-member.sql new file mode 100644 index 0000000000..219d1d9a3d --- /dev/null +++ b/packages/connect-db/migrations/0006_server-member.sql @@ -0,0 +1,12 @@ +CREATE TABLE `server_member` ( + `server_id` text NOT NULL, + `user_id` text NOT NULL, + `added_by_user_id` text NOT NULL, + `created_at` integer NOT NULL, + PRIMARY KEY(`server_id`, `user_id`), + FOREIGN KEY (`server_id`) REFERENCES `server`(`id`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (`added_by_user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action +); +--> statement-breakpoint +CREATE INDEX `server_member_user_id_idx` ON `server_member` (`user_id`); \ No newline at end of file diff --git a/packages/connect-db/migrations/meta/0006_snapshot.json b/packages/connect-db/migrations/meta/0006_snapshot.json new file mode 100644 index 0000000000..e27c9a1a3d --- /dev/null +++ b/packages/connect-db/migrations/meta/0006_snapshot.json @@ -0,0 +1,960 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "a6c23c48-f106-49f2-85e9-43c275a2164b", + "prevId": "7ff3fbcf-840d-4547-8d1f-94d571998114", + "tables": { + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "account_user_id_idx": { + "name": "account_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "audit_log": { + "name": "audit_log", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "detail": { + "name": "detail", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)" + } + }, + "indexes": { + "audit_log_user_id_idx": { + "name": "audit_log_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "audit_log_user_id_user_id_fk": { + "name": "audit_log_user_id_user_id_fk", + "tableFrom": "audit_log", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "connect_code": { + "name": "connect_code", + "columns": { + "code": { + "name": "code", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "server_id": { + "name": "server_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "purpose": { + "name": "purpose", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "consumed_at": { + "name": "consumed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "connect_code_user_id_idx": { + "name": "connect_code_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "connect_code_user_id_user_id_fk": { + "name": "connect_code_user_id_user_id_fk", + "tableFrom": "connect_code", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "connect_code_server_id_server_id_fk": { + "name": "connect_code_server_id_server_id_fk", + "tableFrom": "connect_code", + "tableTo": "server", + "columnsFrom": [ + "server_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "label_claim": { + "name": "label_claim", + "columns": { + "label": { + "name": "label", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "generation": { + "name": "generation", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "label_claim_user_id_idx": { + "name": "label_claim_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "label_claim_user_id_user_id_fk": { + "name": "label_claim_user_id_user_id_fk", + "tableFrom": "label_claim", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "machine": { + "name": "machine", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subdomain": { + "name": "subdomain", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "credential_hash": { + "name": "credential_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "machine_subdomain_unique": { + "name": "machine_subdomain_unique", + "columns": [ + "subdomain" + ], + "isUnique": true + }, + "machine_user_id_idx": { + "name": "machine_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "machine_user_id_user_id_fk": { + "name": "machine_user_id_user_id_fk", + "tableFrom": "machine", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "profile": { + "name": "profile", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "handle": { + "name": "handle", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "profile_handle_unique": { + "name": "profile_handle_unique", + "columns": [ + "handle" + ], + "isUnique": true + } + }, + "foreignKeys": { + "profile_user_id_user_id_fk": { + "name": "profile_user_id_user_id_fk", + "tableFrom": "profile", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "server": { + "name": "server", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'default'" + }, + "subdomain": { + "name": "subdomain", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credential_hash": { + "name": "credential_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "server_subdomain_unique": { + "name": "server_subdomain_unique", + "columns": [ + "subdomain" + ], + "isUnique": true + }, + "server_user_name_idx": { + "name": "server_user_name_idx", + "columns": [ + "user_id", + "name" + ], + "isUnique": true + } + }, + "foreignKeys": { + "server_user_id_user_id_fk": { + "name": "server_user_id_user_id_fk", + "tableFrom": "server", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "server_member": { + "name": "server_member", + "columns": { + "server_id": { + "name": "server_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "added_by_user_id": { + "name": "added_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "server_member_user_id_idx": { + "name": "server_member_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "server_member_server_id_server_id_fk": { + "name": "server_member_server_id_server_id_fk", + "tableFrom": "server_member", + "tableTo": "server", + "columnsFrom": [ + "server_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "server_member_user_id_user_id_fk": { + "name": "server_member_user_id_user_id_fk", + "tableFrom": "server_member", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "server_member_added_by_user_id_user_id_fk": { + "name": "server_member_added_by_user_id_user_id_fk", + "tableFrom": "server_member", + "tableTo": "user", + "columnsFrom": [ + "added_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "server_member_server_id_user_id_pk": { + "columns": [ + "server_id", + "user_id" + ], + "name": "server_member_server_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "session_user_id_idx": { + "name": "session_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "github_login": { + "name": "github_login", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + "identifier" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/packages/connect-db/migrations/meta/_journal.json b/packages/connect-db/migrations/meta/_journal.json index 1b9234becf..81f51a6a63 100644 --- a/packages/connect-db/migrations/meta/_journal.json +++ b/packages/connect-db/migrations/meta/_journal.json @@ -43,6 +43,13 @@ "when": 1783989596863, "tag": "0005_label_claim_triggers", "breakpoints": true + }, + { + "idx": 6, + "version": "6", + "when": 1784389658782, + "tag": "0006_server-member", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/connect-db/src/schema.ts b/packages/connect-db/src/schema.ts index a20691a6ef..bbf503e7d5 100644 --- a/packages/connect-db/src/schema.ts +++ b/packages/connect-db/src/schema.ts @@ -14,6 +14,7 @@ import { sql } from "drizzle-orm"; import { index, integer, + primaryKey, sqliteTable, text, uniqueIndex, @@ -167,6 +168,33 @@ export const server = sqliteTable( (table) => [uniqueIndex("server_user_name_idx").on(table.userId, table.name)], ); +/** + * Non-owner accounts the gate admits to a server, with full owner parity once + * inside. This row is admission ONLY: identity inside the server is + * self-claimed by clients, and the gate's audit log is the sole verified + * access record. The member list is managed exclusively by the server's + * owner. `user_id` index serves the "servers I'm a member of" lookup. + */ +export const serverMember = sqliteTable( + "server_member", + { + serverId: text("server_id") + .notNull() + .references(() => server.id, { onDelete: "cascade" }), + userId: text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + addedByUserId: text("added_by_user_id") + .notNull() + .references(() => user.id), + createdAt: timestampMs("created_at").notNull(), + }, + (table) => [ + primaryKey({ columns: [table.serverId, table.userId] }), + index("server_member_user_id_idx").on(table.userId), + ], +); + /** * One-time codes exchanged during pairing. * - `server-pair`: browser-approval flow mints this; the tunnel client @@ -252,6 +280,7 @@ export const schema = { profile, labelClaim, server, + serverMember, machine, connectCode, auditLog, diff --git a/packages/db/drizzle/0079_multiplayer-collaborators.sql b/packages/db/drizzle/0079_multiplayer-collaborators.sql new file mode 100644 index 0000000000..d7729e8802 --- /dev/null +++ b/packages/db/drizzle/0079_multiplayer-collaborators.sql @@ -0,0 +1,12 @@ +CREATE TABLE `collaborators` ( + `handle` text PRIMARY KEY NOT NULL, + `display_name` text NOT NULL, + `image_url` text, + `first_seen_at` integer NOT NULL, + `last_seen_at` integer NOT NULL +); +--> statement-breakpoint +ALTER TABLE `events` ADD `actor_handle` text;--> statement-breakpoint +ALTER TABLE `pending_interactions` ADD `resolved_by_handle` text;--> statement-breakpoint +ALTER TABLE `queued_thread_messages` ADD `actor_handle` text;--> statement-breakpoint +ALTER TABLE `threads` ADD `created_by_handle` text; \ No newline at end of file diff --git a/packages/db/drizzle/meta/0079_snapshot.json b/packages/db/drizzle/meta/0079_snapshot.json new file mode 100644 index 0000000000..20103588a4 --- /dev/null +++ b/packages/db/drizzle/meta/0079_snapshot.json @@ -0,0 +1,3453 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "a1275ee5-9b07-4638-97a4-9238bd741159", + "prevId": "36647369-2ebb-483c-a0b4-fa1a7beb098c", + "tables": { + "app_settings": { + "name": "app_settings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "caffeinate": { + "name": "caffeinate", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "show_keyboard_hints": { + "name": "show_keyboard_hints", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "show_unhandled_provider_events": { + "name": "show_unhandled_provider_events", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "codex_memory_enabled": { + "name": "codex_memory_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "claude_code_memory_enabled": { + "name": "claude_code_memory_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "codex_subagents_disabled": { + "name": "codex_subagents_disabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "claude_code_subagents_disabled": { + "name": "claude_code_subagents_disabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "claude_code_workflows_disabled": { + "name": "claude_code_workflows_disabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "keybinding_overrides": { + "name": "keybinding_overrides", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "app_theme": { + "name": "app_theme", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "theme_id": { + "name": "theme_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "favicon_color": { + "name": "favicon_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'default'" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "apikey": { + "name": "apikey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "start": { + "name": "start", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "referenceId": { + "name": "referenceId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refillInterval": { + "name": "refillInterval", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refillAmount": { + "name": "refillAmount", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lastRefillAt": { + "name": "lastRefillAt", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rateLimitEnabled": { + "name": "rateLimitEnabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rateLimitTimeWindow": { + "name": "rateLimitTimeWindow", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rateLimitMax": { + "name": "rateLimitMax", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "requestCount": { + "name": "requestCount", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "remaining": { + "name": "remaining", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lastRequest": { + "name": "lastRequest", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expiresAt": { + "name": "expiresAt", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "configId": { + "name": "configId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "apikey_key_unique": { + "name": "apikey_key_unique", + "columns": [ + "key" + ], + "isUnique": true + }, + "apikey_reference_id_idx": { + "name": "apikey_reference_id_idx", + "columns": [ + "referenceId" + ], + "isUnique": false + }, + "apikey_config_id_idx": { + "name": "apikey_config_id_idx", + "columns": [ + "configId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "apikey_referenceId_user_id_fk": { + "name": "apikey_referenceId_user_id_fk", + "tableFrom": "apikey", + "tableTo": "user", + "columnsFrom": [ + "referenceId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "collaborators": { + "name": "collaborators", + "columns": { + "handle": { + "name": "handle", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "first_seen_at": { + "name": "first_seen_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "environments": { + "name": "environments", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "host_id": { + "name": "host_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "managed": { + "name": "managed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "is_git_repo": { + "name": "is_git_repo", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "is_worktree": { + "name": "is_worktree", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "branch_name": { + "name": "branch_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "base_branch": { + "name": "base_branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "default_branch": { + "name": "default_branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "merge_base_branch": { + "name": "merge_base_branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "destroy_attempt_id": { + "name": "destroy_attempt_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "workspace_provision_type": { + "name": "workspace_provision_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'provisioning'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "environments_host_path_idx": { + "name": "environments_host_path_idx", + "columns": [ + "host_id", + "path" + ], + "isUnique": true + }, + "environments_project_idx": { + "name": "environments_project_idx", + "columns": [ + "project_id" + ], + "isUnique": false + }, + "environments_status_idx": { + "name": "environments_status_idx", + "columns": [ + "status" + ], + "isUnique": false + } + }, + "foreignKeys": { + "environments_project_id_projects_id_fk": { + "name": "environments_project_id_projects_id_fk", + "tableFrom": "environments", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "environments_host_id_hosts_id_fk": { + "name": "environments_host_id_hosts_id_fk", + "tableFrom": "environments", + "tableTo": "hosts", + "columnsFrom": [ + "host_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "events": { + "name": "events", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "environment_id": { + "name": "environment_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope_kind": { + "name": "scope_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "turn_id": { + "name": "turn_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider_thread_id": { + "name": "provider_thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sequence": { + "name": "sequence", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "item_kind": { + "name": "item_kind", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_handle": { + "name": "actor_handle", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "data": { + "name": "data", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "events_thread_sequence_idx": { + "name": "events_thread_sequence_idx", + "columns": [ + "thread_id", + "sequence" + ], + "isUnique": true + }, + "events_thread_type_item_kind_sequence_idx": { + "name": "events_thread_type_item_kind_sequence_idx", + "columns": [ + "thread_id", + "type", + "item_kind", + "sequence" + ], + "isUnique": false + }, + "events_thread_type_sequence_idx": { + "name": "events_thread_type_sequence_idx", + "columns": [ + "thread_id", + "type", + "sequence" + ], + "isUnique": false + }, + "events_thread_turn_type_item_sequence_idx": { + "name": "events_thread_turn_type_item_sequence_idx", + "columns": [ + "thread_id", + "turn_id", + "type", + "item_id", + "sequence" + ], + "isUnique": false + }, + "events_environment_idx": { + "name": "events_environment_idx", + "columns": [ + "environment_id" + ], + "isUnique": false + }, + "events_completed_item_truncation_idx": { + "name": "events_completed_item_truncation_idx", + "columns": [ + "item_kind", + "created_at", + "id" + ], + "isUnique": false, + "where": "\"events\".\"type\" = 'item/completed'" + } + }, + "foreignKeys": { + "events_thread_id_threads_id_fk": { + "name": "events_thread_id_threads_id_fk", + "tableFrom": "events", + "tableTo": "threads", + "columnsFrom": [ + "thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "events_environment_id_environments_id_fk": { + "name": "events_environment_id_environments_id_fk", + "tableFrom": "events", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": { + "events_scope_shape_check": { + "name": "events_scope_shape_check", + "value": "(\n (\"events\".\"scope_kind\" = 'turn' AND \"events\".\"turn_id\" IS NOT NULL)\n OR\n (\"events\".\"scope_kind\" = 'thread' AND \"events\".\"turn_id\" IS NULL)\n )" + } + } + }, + "host_daemon_sessions": { + "name": "host_daemon_sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "host_id": { + "name": "host_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "instance_id": { + "name": "instance_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "host_name": { + "name": "host_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "host_type": { + "name": "host_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "data_dir": { + "name": "data_dir", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "protocol_version": { + "name": "protocol_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "heartbeat_interval_ms": { + "name": "heartbeat_interval_ms", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "lease_timeout_ms": { + "name": "lease_timeout_ms", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "lease_expires_at": { + "name": "lease_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "closed_at": { + "name": "closed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "close_reason": { + "name": "close_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "host_daemon_sessions_host_status_idx": { + "name": "host_daemon_sessions_host_status_idx", + "columns": [ + "host_id", + "status" + ], + "isUnique": false + }, + "host_daemon_sessions_host_latest_idx": { + "name": "host_daemon_sessions_host_latest_idx", + "columns": [ + "host_id", + "updated_at", + "created_at", + "id" + ], + "isUnique": false + }, + "host_daemon_sessions_closed_prune_idx": { + "name": "host_daemon_sessions_closed_prune_idx", + "columns": [ + "status", + "closed_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "host_daemon_sessions_host_id_hosts_id_fk": { + "name": "host_daemon_sessions_host_id_hosts_id_fk", + "tableFrom": "host_daemon_sessions", + "tableTo": "hosts", + "columnsFrom": [ + "host_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "hosts": { + "name": "hosts", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "connect_machine_id": { + "name": "connect_machine_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "destroyed_at": { + "name": "destroyed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_rejected_protocol_version": { + "name": "last_rejected_protocol_version", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "hosts_last_seen_idx": { + "name": "hosts_last_seen_idx", + "columns": [ + "last_seen_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plugins": { + "name": "plugins", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provenance": { + "name": "provenance", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'direct'" + }, + "catalog_entry_id": { + "name": "catalog_entry_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_kind": { + "name": "source_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'path'" + }, + "source_path": { + "name": "source_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_builtin_name": { + "name": "source_builtin_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_npm_package": { + "name": "source_npm_package", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_npm_registry": { + "name": "source_npm_registry", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_npm_requested_spec": { + "name": "source_npm_requested_spec", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_npm_spec_kind": { + "name": "source_npm_spec_kind", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_git_url": { + "name": "source_git_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_git_subdirectory": { + "name": "source_git_subdirectory", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_git_requested_ref": { + "name": "source_git_requested_ref", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_git_ref_kind": { + "name": "source_git_ref_kind", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "npm_resolved_version": { + "name": "npm_resolved_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "npm_integrity": { + "name": "npm_integrity", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "git_resolved_commit": { + "name": "git_resolved_commit", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_update_check_at": { + "name": "last_update_check_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "available_compatible_version": { + "name": "available_compatible_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "newest_incompatible_version": { + "name": "newest_incompatible_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "update_status_detail": { + "name": "update_status_detail", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_failure_version": { + "name": "last_failure_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_failure_at": { + "name": "last_failure_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_failure_detail": { + "name": "last_failure_detail", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active_artifact_id": { + "name": "active_artifact_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "normalization_version": { + "name": "normalization_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "root_dir": { + "name": "root_dir", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "removed_at": { + "name": "removed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "installed_at": { + "name": "installed_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "plugins_active_artifact_id_plugin_artifacts_id_fk": { + "name": "plugins_active_artifact_id_plugin_artifacts_id_fk", + "tableFrom": "plugins", + "tableTo": "plugin_artifacts", + "columnsFrom": [ + "active_artifact_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "maintenance_scan_cursors": { + "name": "maintenance_scan_cursors", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "policy": { + "name": "policy", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "item_kind": { + "name": "item_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "output_path": { + "name": "output_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_created_at": { + "name": "last_created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "last_event_id": { + "name": "last_event_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "maintenance_scan_cursors_path_idx": { + "name": "maintenance_scan_cursors_path_idx", + "columns": [ + "policy", + "version", + "item_kind", + "output_path" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "pending_interactions": { + "name": "pending_interactions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "origin_kind": { + "name": "origin_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'provider'" + }, + "turn_id": { + "name": "turn_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider_thread_id": { + "name": "provider_thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider_request_id": { + "name": "provider_request_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "plugin_id": { + "name": "plugin_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "renderer_id": { + "name": "renderer_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resolution": { + "name": "resolution", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resolved_by_handle": { + "name": "resolved_by_handle", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status_reason": { + "name": "status_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resolved_at": { + "name": "resolved_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "pending_interactions_provider_request_idx": { + "name": "pending_interactions_provider_request_idx", + "columns": [ + "provider_id", + "provider_thread_id", + "provider_request_id" + ], + "isUnique": true + }, + "pending_interactions_thread_created_idx": { + "name": "pending_interactions_thread_created_idx", + "columns": [ + "thread_id", + "created_at" + ], + "isUnique": false + }, + "pending_interactions_thread_status_created_idx": { + "name": "pending_interactions_thread_status_created_idx", + "columns": [ + "thread_id", + "status", + "created_at" + ], + "isUnique": false + }, + "pending_interactions_status_created_idx": { + "name": "pending_interactions_status_created_idx", + "columns": [ + "status", + "created_at" + ], + "isUnique": false + }, + "pending_interactions_plugin_status_created_idx": { + "name": "pending_interactions_plugin_status_created_idx", + "columns": [ + "plugin_id", + "status", + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "pending_interactions_thread_id_threads_id_fk": { + "name": "pending_interactions_thread_id_threads_id_fk", + "tableFrom": "pending_interactions", + "tableTo": "threads", + "columnsFrom": [ + "thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plugin_artifacts": { + "name": "plugin_artifacts", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "plugin_id": { + "name": "plugin_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_kind": { + "name": "source_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "npm_resolved_version": { + "name": "npm_resolved_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "git_resolved_commit": { + "name": "git_resolved_commit", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integrity": { + "name": "integrity", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "validation_result": { + "name": "validation_result", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "validated_at": { + "name": "validated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "plugin_artifacts_plugin_idx": { + "name": "plugin_artifacts_plugin_idx", + "columns": [ + "plugin_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plugin_kv": { + "name": "plugin_kv", + "columns": { + "plugin_id": { + "name": "plugin_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "plugin_kv_plugin_id_key_pk": { + "columns": [ + "plugin_id", + "key" + ], + "name": "plugin_kv_plugin_id_key_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plugin_schedules": { + "name": "plugin_schedules", + "columns": { + "plugin_id": { + "name": "plugin_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cron": { + "name": "cron", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "next_run_at": { + "name": "next_run_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_run_at": { + "name": "last_run_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_status": { + "name": "last_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "plugin_schedules_plugin_id_name_pk": { + "columns": [ + "plugin_id", + "name" + ], + "name": "plugin_schedules_plugin_id_name_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plugin_settings": { + "name": "plugin_settings", + "columns": { + "plugin_id": { + "name": "plugin_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "plugin_settings_plugin_id_key_pk": { + "columns": [ + "plugin_id", + "key" + ], + "name": "plugin_settings_plugin_id_key_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plugin_state_snapshots": { + "name": "plugin_state_snapshots", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "plugin_id": { + "name": "plugin_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "from_artifact_id": { + "name": "from_artifact_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "to_artifact_id": { + "name": "to_artifact_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "snapshot_path": { + "name": "snapshot_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "database_path": { + "name": "database_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "state_path": { + "name": "state_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "secrets_path": { + "name": "secrets_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "registration_path": { + "name": "registration_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rollback_candidate_version": { + "name": "rollback_candidate_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rollback_source_fingerprint": { + "name": "rollback_source_fingerprint", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rollback_bb_version": { + "name": "rollback_bb_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rollback_sdk_version": { + "name": "rollback_sdk_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rollback_detail": { + "name": "rollback_detail", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "retained_until": { + "name": "retained_until", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "plugin_state_snapshots_plugin_idx": { + "name": "plugin_state_snapshots_plugin_idx", + "columns": [ + "plugin_id" + ], + "isUnique": false + }, + "plugin_state_snapshots_retention_idx": { + "name": "plugin_state_snapshots_retention_idx", + "columns": [ + "retained_until" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "project_execution_defaults": { + "name": "project_execution_defaults", + "columns": { + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "service_tier": { + "name": "service_tier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reasoning_level": { + "name": "reasoning_level", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission_mode": { + "name": "permission_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "project_execution_defaults_project_idx": { + "name": "project_execution_defaults_project_idx", + "columns": [ + "project_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "project_execution_defaults_project_id_projects_id_fk": { + "name": "project_execution_defaults_project_id_projects_id_fk", + "tableFrom": "project_execution_defaults", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "project_sources": { + "name": "project_sources", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "host_id": { + "name": "host_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_default": { + "name": "is_default", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "project_sources_project_idx": { + "name": "project_sources_project_idx", + "columns": [ + "project_id" + ], + "isUnique": false + }, + "project_sources_host_idx": { + "name": "project_sources_host_idx", + "columns": [ + "host_id" + ], + "isUnique": false + }, + "project_sources_project_host_idx": { + "name": "project_sources_project_host_idx", + "columns": [ + "project_id", + "host_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "project_sources_project_id_projects_id_fk": { + "name": "project_sources_project_id_projects_id_fk", + "tableFrom": "project_sources", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "project_sources_host_id_hosts_id_fk": { + "name": "project_sources_host_id_hosts_id_fk", + "tableFrom": "project_sources", + "tableTo": "hosts", + "columnsFrom": [ + "host_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": { + "project_sources_shape_check": { + "name": "project_sources_shape_check", + "value": "(\n \"project_sources\".\"type\" = 'local_path' AND \"project_sources\".\"host_id\" IS NOT NULL AND \"project_sources\".\"path\" IS NOT NULL\n )" + } + } + }, + "projects": { + "name": "projects", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'standard'" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "git_remote_url": { + "name": "git_remote_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sort_key": { + "name": "sort_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'V'" + }, + "deleted_at": { + "name": "deleted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "projects_updated_idx": { + "name": "projects_updated_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + }, + "projects_deleted_idx": { + "name": "projects_deleted_idx", + "columns": [ + "deleted_at" + ], + "isUnique": false + }, + "projects_sort_idx": { + "name": "projects_sort_idx", + "columns": [ + "sort_key", + "id" + ], + "isUnique": false + }, + "projects_personal_singleton_idx": { + "name": "projects_personal_singleton_idx", + "columns": [ + "kind" + ], + "isUnique": true, + "where": "\"projects\".\"kind\" = 'personal'" + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "prompt_history_entries": { + "name": "prompt_history_entries", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "request_sequence": { + "name": "request_sequence", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "input": { + "name": "input", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "prompt_history_entries_thread_request_idx": { + "name": "prompt_history_entries_thread_request_idx", + "columns": [ + "thread_id", + "request_sequence" + ], + "isUnique": true + }, + "prompt_history_entries_project_scope_created_idx": { + "name": "prompt_history_entries_project_scope_created_idx", + "columns": [ + "project_id", + "scope", + "created_at", + "request_sequence", + "id" + ], + "isUnique": false + }, + "prompt_history_entries_thread_scope_created_idx": { + "name": "prompt_history_entries_thread_scope_created_idx", + "columns": [ + "thread_id", + "scope", + "created_at", + "request_sequence", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "prompt_history_entries_project_id_projects_id_fk": { + "name": "prompt_history_entries_project_id_projects_id_fk", + "tableFrom": "prompt_history_entries", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "prompt_history_entries_thread_id_threads_id_fk": { + "name": "prompt_history_entries_thread_id_threads_id_fk", + "tableFrom": "prompt_history_entries", + "tableTo": "threads", + "columnsFrom": [ + "thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "queued_thread_messages": { + "name": "queued_thread_messages", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sender_thread_id": { + "name": "sender_thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_handle": { + "name": "actor_handle", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reasoning_level": { + "name": "reasoning_level", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission_mode": { + "name": "permission_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "service_tier": { + "name": "service_tier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_with_next": { + "name": "group_with_next", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "claimed_at": { + "name": "claimed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "claim_token": { + "name": "claim_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sort_key": { + "name": "sort_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "queued_thread_messages_thread_created_idx": { + "name": "queued_thread_messages_thread_created_idx", + "columns": [ + "thread_id", + "created_at", + "id" + ], + "isUnique": false + }, + "queued_thread_messages_thread_sort_idx": { + "name": "queued_thread_messages_thread_sort_idx", + "columns": [ + "thread_id", + "sort_key", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "queued_thread_messages_thread_id_threads_id_fk": { + "name": "queued_thread_messages_thread_id_threads_id_fk", + "tableFrom": "queued_thread_messages", + "tableTo": "threads", + "columnsFrom": [ + "thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "system_experiments": { + "name": "system_experiments", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "claude_code_mock_cli_traffic": { + "name": "claude_code_mock_cli_traffic", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "plugins": { + "name": "plugins", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "terminal_sessions": { + "name": "terminal_sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "environment_id": { + "name": "environment_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "host_id": { + "name": "host_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "daemon_session_id": { + "name": "daemon_session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "initial_cwd": { + "name": "initial_cwd", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cols": { + "name": "cols", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rows": { + "name": "rows", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "exit_code": { + "name": "exit_code", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "close_reason": { + "name": "close_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_user_input_at": { + "name": "last_user_input_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "terminal_sessions_thread_status_updated_idx": { + "name": "terminal_sessions_thread_status_updated_idx", + "columns": [ + "thread_id", + "status", + "updated_at" + ], + "isUnique": false + }, + "terminal_sessions_environment_status_idx": { + "name": "terminal_sessions_environment_status_idx", + "columns": [ + "environment_id", + "status" + ], + "isUnique": false + }, + "terminal_sessions_host_status_idx": { + "name": "terminal_sessions_host_status_idx", + "columns": [ + "host_id", + "status" + ], + "isUnique": false + }, + "terminal_sessions_daemon_session_idx": { + "name": "terminal_sessions_daemon_session_idx", + "columns": [ + "daemon_session_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "terminal_sessions_thread_id_threads_id_fk": { + "name": "terminal_sessions_thread_id_threads_id_fk", + "tableFrom": "terminal_sessions", + "tableTo": "threads", + "columnsFrom": [ + "thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "terminal_sessions_environment_id_environments_id_fk": { + "name": "terminal_sessions_environment_id_environments_id_fk", + "tableFrom": "terminal_sessions", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "terminal_sessions_host_id_hosts_id_fk": { + "name": "terminal_sessions_host_id_hosts_id_fk", + "tableFrom": "terminal_sessions", + "tableTo": "hosts", + "columnsFrom": [ + "host_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "terminal_sessions_daemon_session_id_host_daemon_sessions_id_fk": { + "name": "terminal_sessions_daemon_session_id_host_daemon_sessions_id_fk", + "tableFrom": "terminal_sessions", + "tableTo": "host_daemon_sessions", + "columnsFrom": [ + "daemon_session_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "thread_dynamic_context_file_states": { + "name": "thread_dynamic_context_file_states", + "columns": { + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_key": { + "name": "file_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_status": { + "name": "content_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "shown_at": { + "name": "shown_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "thread_dynamic_context_file_states_thread_file_idx": { + "name": "thread_dynamic_context_file_states_thread_file_idx", + "columns": [ + "thread_id", + "file_key" + ], + "isUnique": true + } + }, + "foreignKeys": { + "thread_dynamic_context_file_states_thread_id_threads_id_fk": { + "name": "thread_dynamic_context_file_states_thread_id_threads_id_fk", + "tableFrom": "thread_dynamic_context_file_states", + "tableTo": "threads", + "columnsFrom": [ + "thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "thread_search_segments": { + "name": "thread_search_segments", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_kind": { + "name": "source_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_key": { + "name": "source_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_seq": { + "name": "source_seq", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "text": { + "name": "text", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "thread_search_segments_source_idx": { + "name": "thread_search_segments_source_idx", + "columns": [ + "thread_id", + "source_kind", + "source_key" + ], + "isUnique": true + }, + "thread_search_segments_thread_idx": { + "name": "thread_search_segments_thread_idx", + "columns": [ + "thread_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "thread_search_segments_thread_id_threads_id_fk": { + "name": "thread_search_segments_thread_id_threads_id_fk", + "tableFrom": "thread_search_segments", + "tableTo": "threads", + "columnsFrom": [ + "thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "thread_sections": { + "name": "thread_sections", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "thread_sections_name_idx": { + "name": "thread_sections_name_idx", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "thread_tabs": { + "name": "thread_tabs", + "columns": { + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "tabs_json": { + "name": "tabs_json", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "revision": { + "name": "revision", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "thread_tabs_thread_id_threads_id_fk": { + "name": "thread_tabs_thread_id_threads_id_fk", + "tableFrom": "thread_tabs", + "tableTo": "threads", + "columnsFrom": [ + "thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "threads": { + "name": "threads", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "environment_id": { + "name": "environment_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_override": { + "name": "model_override", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reasoning_level_override": { + "name": "reasoning_level_override", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "title_fallback": { + "name": "title_fallback", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'starting'" + }, + "parent_thread_id": { + "name": "parent_thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_thread_id": { + "name": "source_thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "origin_kind": { + "name": "origin_kind", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "child_origin": { + "name": "child_origin", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "origin_plugin_id": { + "name": "origin_plugin_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by_handle": { + "name": "created_by_handle", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'visible'" + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "pinned_at": { + "name": "pinned_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "pin_sort_key": { + "name": "pin_sort_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_read_at": { + "name": "last_read_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "latest_attention_at": { + "name": "latest_attention_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "threads_project_updated_idx": { + "name": "threads_project_updated_idx", + "columns": [ + "project_id", + "updated_at" + ], + "isUnique": false + }, + "threads_project_archived_deleted_idx": { + "name": "threads_project_archived_deleted_idx", + "columns": [ + "project_id", + "archived_at", + "deleted_at", + "id" + ], + "isUnique": false + }, + "threads_pin_sort_idx": { + "name": "threads_pin_sort_idx", + "columns": [ + "archived_at", + "deleted_at", + "pin_sort_key", + "id" + ], + "isUnique": false, + "where": "\"threads\".\"pinned_at\" IS NOT NULL" + }, + "threads_environment_idx": { + "name": "threads_environment_idx", + "columns": [ + "environment_id" + ], + "isUnique": false + }, + "threads_parent_idx": { + "name": "threads_parent_idx", + "columns": [ + "parent_thread_id" + ], + "isUnique": false + }, + "threads_source_origin_idx": { + "name": "threads_source_origin_idx", + "columns": [ + "source_thread_id", + "origin_kind" + ], + "isUnique": false + }, + "threads_section_archived_deleted_idx": { + "name": "threads_section_archived_deleted_idx", + "columns": [ + "section_id", + "archived_at", + "deleted_at", + "id" + ], + "isUnique": false + }, + "threads_archived_status_idx": { + "name": "threads_archived_status_idx", + "columns": [ + "archived_at", + "status" + ], + "isUnique": false + }, + "threads_environment_archived_deleted_idx": { + "name": "threads_environment_archived_deleted_idx", + "columns": [ + "environment_id", + "archived_at", + "deleted_at" + ], + "isUnique": false + }, + "threads_active_maintenance_idx": { + "name": "threads_active_maintenance_idx", + "columns": [ + "status" + ], + "isUnique": false, + "where": "\"threads\".\"deleted_at\" IS NULL" + } + }, + "foreignKeys": { + "threads_project_id_projects_id_fk": { + "name": "threads_project_id_projects_id_fk", + "tableFrom": "threads", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "threads_environment_id_environments_id_fk": { + "name": "threads_environment_id_environments_id_fk", + "tableFrom": "threads", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "threads_section_id_thread_sections_id_fk": { + "name": "threads_section_id_thread_sections_id_fk", + "tableFrom": "threads", + "tableTo": "thread_sections", + "columnsFrom": [ + "section_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "threads_parent_thread_id_threads_id_fk": { + "name": "threads_parent_thread_id_threads_id_fk", + "tableFrom": "threads", + "tableTo": "threads", + "columnsFrom": [ + "parent_thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "threads_source_thread_id_threads_id_fk": { + "name": "threads_source_thread_id_threads_id_fk", + "tableFrom": "threads", + "tableTo": "threads", + "columnsFrom": [ + "source_thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index ae84df6776..cb006668e7 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -554,6 +554,13 @@ "when": 1784311522462, "tag": "0078_permission_modes", "breakpoints": true + }, + { + "idx": 79, + "version": "6", + "when": 1784389648607, + "tag": "0079_multiplayer-collaborators", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/db/src/migrate.ts b/packages/db/src/migrate.ts index e29f4c649b..54a1af5e58 100644 --- a/packages/db/src/migrate.ts +++ b/packages/db/src/migrate.ts @@ -190,6 +190,12 @@ const pendingInteractionColumns: ExpectedColumn[] = [ { name: "status", type: "text", notNull: true, primaryKey: false }, { name: "payload", type: "text", notNull: true, primaryKey: false }, { name: "resolution", type: "text", notNull: false, primaryKey: false }, + { + name: "resolved_by_handle", + type: "text", + notNull: false, + primaryKey: false, + }, { name: "status_reason", type: "text", diff --git a/packages/db/src/schema.ts b/packages/db/src/schema.ts index 0ee444312b..b5b1cdfe79 100644 --- a/packages/db/src/schema.ts +++ b/packages/db/src/schema.ts @@ -495,6 +495,9 @@ export const threads = sqliteTable( // Id of the plugin that spawned this thread (create origin "plugin"). // NULL for every other origin. originPluginId: text("origin_plugin_id"), + // Normalized handle of the human who created the thread. NULL = created by + // an agent/plugin/system origin or pre-multiplayer history. + createdByHandle: text("created_by_handle"), visibility: text("visibility", { enum: threadVisibilityValues }) .notNull() .default("visible"), @@ -612,6 +615,23 @@ export const threadDynamicContextFileStates = sqliteTable( ], ); +// Claimed multiplayer identities, upserted from the x-bb-claimed-identity +// handshake on request/socket connect. bb never verifies these: admission is +// enforced at the boundary (connect gate / network) and any admitted client +// has owner parity, so attribution is honor-system by design. Keyed by +// normalized handle — the same handle on two devices is the same person; a +// rename creates a new collaborator and history keeps the old handle. +// Attribution columns elsewhere store the handle as plain text (no FK): adding +// an FK would force drizzle to rebuild the large events table, and dangling +// handles are harmless soft references. +export const collaborators = sqliteTable("collaborators", { + handle: text("handle").primaryKey(), + displayName: text("display_name").notNull(), + imageUrl: text("image_url"), + firstSeenAt: integer("first_seen_at").notNull(), + lastSeenAt: integer("last_seen_at").notNull(), +}); + export const events = sqliteTable( "events", { @@ -629,6 +649,9 @@ export const events = sqliteTable( type: text("type").$type().notNull(), itemId: text("item_id"), itemKind: text("item_kind").$type(), + // Normalized handle of the human who initiated this event. NULL = not + // human-initiated (agent/provider/system) or pre-multiplayer history. + actorHandle: text("actor_handle"), data: text("data").notNull().default("{}"), createdAt: integer("created_at").notNull(), }, @@ -738,6 +761,10 @@ export const queuedThreadMessages = sqliteTable( .references(() => threads.id, { onDelete: "cascade" }), content: text("content").notNull(), senderThreadId: text("sender_thread_id"), + // Normalized handle of the human who queued the message, carried through + // so attribution survives the queue. NULL = queued by a non-human sender + // (e.g. another thread) or pre-multiplayer history. + actorHandle: text("actor_handle"), model: text("model").notNull(), reasoningLevel: text("reasoning_level").notNull(), permissionMode: text("permission_mode").$type().notNull(), @@ -868,6 +895,9 @@ export const pendingInteractions = sqliteTable( status: text("status").$type().notNull(), payload: text("payload").notNull(), resolution: text("resolution"), + // Normalized handle of the human who resolved the interaction. NULL = + // unresolved, resolved by system/expiry, or pre-multiplayer history. + resolvedByHandle: text("resolved_by_handle"), statusReason: text("status_reason"), createdAt: integer("created_at").notNull(), expiresAt: integer("expires_at"), diff --git a/packages/db/test/migrate.test.ts b/packages/db/test/migrate.test.ts index 312c13e436..eabb89782b 100644 --- a/packages/db/test/migrate.test.ts +++ b/packages/db/test/migrate.test.ts @@ -213,18 +213,54 @@ interface SeededLargeValueBackfillValues { const __dirname = dirname(fileURLToPath(import.meta.url)); +const migrationJournalEntries = ( + JSON.parse( + readFileSync(resolve(__dirname, "../drizzle/meta/_journal.json"), "utf-8"), + ) as { entries: { tag: string; when: number }[] } +).entries; + const latestMigrationWhen = Math.max( - ...( - JSON.parse( - readFileSync( - resolve(__dirname, "../drizzle/meta/_journal.json"), - "utf-8", - ), - ) as { entries: { when: number }[] } - ).entries.map((entry) => entry.when), + ...migrationJournalEntries.map((entry) => entry.when), +); + +function migrationWhenByTag(tag: string): number { + const entry = migrationJournalEntries.find((e) => e.tag === tag); + if (entry === undefined) { + throw new Error(`migration journal entry not found: ${tag}`); + } + return entry.when; +} + +const permissionModesMigrationWhen = migrationWhenByTag( + "0078_permission_modes", +); + +const multiplayerAttributionMigrationWhen = migrationWhenByTag( + "0079_multiplayer-collaborators", ); +// 0079 adds the collaborators table and four attribution columns. Tests that +// rewind and replay it must strip those artifacts first or its CREATE/ALTER +// statements collide with the head schema. +function dropMultiplayerAttributionArtifacts(db: DbConnection): void { + db.$client.prepare("DROP TABLE IF EXISTS collaborators").run(); + for (const [table, column] of [ + ["events", "actor_handle"], + ["threads", "created_by_handle"], + ["queued_thread_messages", "actor_handle"], + ["pending_interactions", "resolved_by_handle"], + ] as const) { + const exists = db.$client + .prepare("SELECT 1 FROM pragma_table_info(?) WHERE name = ?") + .get(table, column); + if (exists !== undefined) { + db.$client.prepare(`ALTER TABLE ${table} DROP COLUMN ${column}`).run(); + } + } +} + function dropRewindAddedTables(db: DbConnection): void { + dropMultiplayerAttributionArtifacts(db); // Several tests migrate to head, rewind the schema to a legacy state, then // re-apply forward. Tables added by recent migrations must be dropped as part // of that rewind so the forward re-migrate can re-create them: the automations @@ -1184,9 +1220,10 @@ describe("migrate", () => { inheritedQueue.id, fallbackQueue.id, ); + dropMultiplayerAttributionArtifacts(db); db.$client - .prepare("DELETE FROM __drizzle_migrations WHERE created_at = ?") - .run(latestMigrationWhen); + .prepare("DELETE FROM __drizzle_migrations WHERE created_at >= ?") + .run(permissionModesMigrationWhen); migrate(db); @@ -1461,6 +1498,16 @@ describe("migrate", () => { `, ) .run("branch-local-thread-tabs", branchLocalThreadTabsMigrationWhen); + // The branch-local repair rebuilds pending_interactions at its 0059 + // shape, so 0079 must replay afterwards to restore resolved_by_handle — + // mirroring the real branch-local ledger, which has no rows after the + // branch point. + dropMultiplayerAttributionArtifacts(db); + db.$client + .prepare( + "DELETE FROM __drizzle_migrations WHERE created_at >= ?", + ) + .run(multiplayerAttributionMigrationWhen); migrate(db); @@ -1567,6 +1614,7 @@ describe("migrate", () => { "ALTER TABLE system_experiments ADD COLUMN thread_splits integer DEFAULT false NOT NULL", ) .run(); + dropMultiplayerAttributionArtifacts(db); db.$client .prepare( "DELETE FROM __drizzle_migrations WHERE created_at = ?", @@ -1659,6 +1707,7 @@ describe("migrate", () => { ALTER TABLE system_experiments ADD COLUMN thread_splits integer DEFAULT false NOT NULL; `); + dropMultiplayerAttributionArtifacts(db); db.$client .prepare( "DELETE FROM __drizzle_migrations WHERE created_at >= ?", @@ -3188,6 +3237,8 @@ describe("migrate", () => { "item_kind", "data", "created_at", + // Re-appended by the 0079 replay; ALTER TABLE ADD places it last. + "actor_handle", ]); const eventIndexNames = readIndexNames({ db, diff --git a/packages/db/test/schema.test.ts b/packages/db/test/schema.test.ts index 66f7fa73e4..3c6507e4d0 100644 --- a/packages/db/test/schema.test.ts +++ b/packages/db/test/schema.test.ts @@ -72,7 +72,7 @@ describe("db rebuild schema", () => { ) .all(); - expect(columns).toHaveLength(17); + expect(columns).toHaveLength(18); expect(columns).toEqual( expect.arrayContaining([ { name: "id", type: "text", notNull: 1, primaryKey: 1 }, @@ -92,6 +92,12 @@ describe("db rebuild schema", () => { { name: "status", type: "text", notNull: 1, primaryKey: 0 }, { name: "payload", type: "text", notNull: 1, primaryKey: 0 }, { name: "resolution", type: "text", notNull: 0, primaryKey: 0 }, + { + name: "resolved_by_handle", + type: "text", + notNull: 0, + primaryKey: 0, + }, { name: "status_reason", type: "text", notNull: 0, primaryKey: 0 }, { name: "created_at", type: "integer", notNull: 1, primaryKey: 0 }, { name: "expires_at", type: "integer", notNull: 0, primaryKey: 0 }, diff --git a/packages/domain/src/change-kinds.ts b/packages/domain/src/change-kinds.ts index 7d1f17a0fa..8012fa8fa1 100644 --- a/packages/domain/src/change-kinds.ts +++ b/packages/domain/src/change-kinds.ts @@ -130,9 +130,22 @@ export const unsubscribeMessageSchema = z.object({ }); export type UnsubscribeMessage = z.infer; +/** + * Ephemeral composer-typing signal. The server folds it into presence state + * with a short TTL; it is never persisted. Older servers drop the message on + * parse, which is an acceptable degradation for a purely cosmetic signal. + */ +export const typingMessageSchema = z.object({ + type: z.literal("typing"), + threadId: z.string().min(1), + typing: z.boolean(), +}); +export type TypingMessage = z.infer; + export const clientMessageSchema = z.discriminatedUnion("type", [ subscribeMessageSchema, unsubscribeMessageSchema, + typingMessageSchema, ]); export type ClientMessage = z.infer; @@ -239,6 +252,44 @@ export const systemChangedMessageSchema = z .strict(); export type SystemChangedMessage = z.infer; +/** + * Multiplayer presence broadcasts. Viewer sets are derived server-side from + * live websocket subscriptions (a socket subscribed to thread-detail: with + * a claimed identity is "viewing"); nothing is persisted. `thread-presence` + * goes to that thread's detail subscribers; `presence-summary` is the compact + * sidebar form sent to thread-list subscribers. + */ +export const presenceViewerSchema = z + .object({ + handle: z.string().min(1), + displayName: z.string().min(1), + // null = no avatar; clients render initials. + imageUrl: z.string().nullable(), + typing: z.boolean(), + }) + .strict(); +export type PresenceViewer = z.infer; + +export const threadPresenceMessageSchema = z + .object({ + type: z.literal("thread-presence"), + threadId: z.string().min(1), + viewers: z.array(presenceViewerSchema).readonly(), + }) + .strict(); +export type ThreadPresenceMessage = z.infer; + +export const presenceSummaryMessageSchema = z + .object({ + type: z.literal("presence-summary"), + // threadId -> handles currently viewing that thread. + threads: z.record(z.string(), z.array(z.string()).readonly()), + }) + .strict(); +export type PresenceSummaryMessage = z.infer< + typeof presenceSummaryMessageSchema +>; + export const changedMessageSchema = z.discriminatedUnion("entity", [ threadChangedMessageSchema, projectChangedMessageSchema, @@ -325,3 +376,27 @@ export const changedMessageLenientSchema = z.discriminatedUnion("entity", [ hostChangedMessageLenientSchema, systemChangedMessageLenientSchema, ]); + +/** + * Lenient inbound counterparts for presence broadcasts: unknown fields are + * stripped and additive per-viewer fields from a newer server degrade to + * defaults instead of dropping the whole roster. Output remains assignable to + * the strict message types. + */ +export const threadPresenceMessageLenientSchema = z.object({ + type: z.literal("thread-presence"), + threadId: z.string().min(1), + viewers: z.array( + z.object({ + handle: z.string().min(1), + displayName: z.string().min(1), + imageUrl: z.string().nullable().catch(null), + typing: z.boolean().catch(false), + }), + ), +}); + +export const presenceSummaryMessageLenientSchema = z.object({ + type: z.literal("presence-summary"), + threads: z.record(z.string(), z.array(z.string())), +}); diff --git a/packages/domain/src/claimed-identity.ts b/packages/domain/src/claimed-identity.ts new file mode 100644 index 0000000000..d14be9b113 --- /dev/null +++ b/packages/domain/src/claimed-identity.ts @@ -0,0 +1,67 @@ +import { z } from "zod"; + +/** + * Multiplayer identity is CLAIMED, not verified: every client self-asserts who + * it is via this header, on API requests and the /ws upgrade. Admission is + * enforced entirely at the boundary (connect gate membership, tailnet ACLs, or + * an explicitly opened network bind); anyone admitted has owner parity and + * could execute code regardless, so attribution is honor-system by design. + * The only verified record is the connect gate's admission audit log. + * + * Collaborators are keyed by normalized handle: the same handle on two devices + * is the same person. `clientId` is a per-device hint used only for presence + * bookkeeping, never for identity. + */ +export const CLAIMED_IDENTITY_HEADER = "x-bb-claimed-identity"; + +export const claimedIdentitySchema = z + .object({ + handle: z.string().min(1).max(64), + displayName: z.string().min(1).max(128), + // null = this person has no avatar; clients render initials instead. + imageUrl: z.string().max(2048).nullable(), + clientId: z.string().min(1).max(64), + }) + .strict(); +export type ClaimedIdentity = z.infer; + +/** + * Canonical form used as the collaborator key. Case and surrounding whitespace + * never distinguish people ("Sawyer" and "sawyer " are the same collaborator). + */ +export function normalizeHandle(raw: string): string { + return raw.normalize("NFKC").trim().toLowerCase(); +} + +/** Header value: URI-encoded JSON (ASCII-safe, portable browser/node). */ +export function encodeClaimedIdentityHeader(identity: ClaimedIdentity): string { + return encodeURIComponent(JSON.stringify(identity)); +} + +/** + * Boundary parser for the freeform header. Returns the identity with its + * handle normalized, or null when the value is absent or malformed — callers + * fall back to their default local identity rather than failing the request. + */ +export function decodeClaimedIdentityHeader( + value: string | null | undefined, +): ClaimedIdentity | null { + if (!value) { + return null; + } + let parsed: unknown; + try { + parsed = JSON.parse(decodeURIComponent(value)); + } catch { + return null; + } + const result = claimedIdentitySchema.safeParse(parsed); + if (!result.success) { + return null; + } + const handle = normalizeHandle(result.data.handle); + if (handle.length === 0) { + return null; + } + return { ...result.data, handle }; +} diff --git a/packages/domain/src/index.ts b/packages/domain/src/index.ts index 6193ca0287..5c5d19e9cc 100644 --- a/packages/domain/src/index.ts +++ b/packages/domain/src/index.ts @@ -9,6 +9,7 @@ export * from "./app-keybindings.js"; export * from "./app-theme.js"; export * from "./background-task.js"; export * from "./change-kinds.js"; +export * from "./claimed-identity.js"; export * from "./claude-task-tools.js"; export * from "./debounced-callback-scheduler.js"; export * from "./environment-lifecycle.js"; From 9571629e3f9a172b9af357701bb0516f60a7f5c5 Mon Sep 17 00:00:00 2001 From: Sawyer Hood Date: Sat, 18 Jul 2026 09:10:18 -0700 Subject: [PATCH 2/8] Multiplayer wave 1: gate membership admission and claimed-identity plumbing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WS1 (connect cloud): the gate admits invited members alongside the owner — non-owner sessions are checked against server_member for server-kind labels (desktop credentials stay owner-only), and admission fails closed unless a debounced member-admitted audit_log row lands, since that log is the system's only verified access record. Owner-session member management API on the worker: GET/POST /api/servers/:serverId/members and DELETE .../members/:userId (403 non-owner, 404 unknown handle, 409 duplicate, 400 owner-handle), with member-added/member-removed audit rows. WS2 (local server): every /api/v1 request and /ws upgrade resolves a claimed actor from x-bb-claimed-identity, falling back to a startup local-operator identity (OS username/hostname); collaborators are upserted through a new @bb/db data module with a 60s same-content debounce; sockets carry their actor via ws/socket-actors (registered at open, released on close) for the upcoming presence work. The server still never authorizes by identity. Co-Authored-By: Claude Fable 5 --- apps/connect/src/members.test.ts | 433 ++++++++++++++++++ apps/connect/src/members.ts | 379 +++++++++++++++ apps/connect/src/worker.test.ts | 90 ++++ apps/connect/src/worker.ts | 22 +- apps/server/src/server.ts | 30 +- apps/server/src/services/actors.ts | 118 +++++ apps/server/src/ws/client-protocol.ts | 2 + apps/server/src/ws/socket-actors.ts | 18 + apps/server/test/app/client-protocol.test.ts | 24 + apps/server/test/app/socket-actors.test.ts | 26 ++ .../test/public/public-request-actors.test.ts | 78 ++++ apps/server/test/services/actors.test.ts | 92 ++++ packages/db/src/data/collaborators.ts | 54 +++ packages/db/src/data/index.ts | 10 + packages/db/test/data/collaborators.test.ts | 74 +++ 15 files changed, 1439 insertions(+), 11 deletions(-) create mode 100644 apps/connect/src/members.test.ts create mode 100644 apps/connect/src/members.ts create mode 100644 apps/server/src/services/actors.ts create mode 100644 apps/server/src/ws/socket-actors.ts create mode 100644 apps/server/test/app/socket-actors.test.ts create mode 100644 apps/server/test/public/public-request-actors.test.ts create mode 100644 apps/server/test/services/actors.test.ts create mode 100644 packages/db/src/data/collaborators.ts create mode 100644 packages/db/test/data/collaborators.test.ts diff --git a/apps/connect/src/members.test.ts b/apps/connect/src/members.test.ts new file mode 100644 index 0000000000..e89aebe870 --- /dev/null +++ b/apps/connect/src/members.test.ts @@ -0,0 +1,433 @@ +import { readdirSync, readFileSync } from "node:fs"; +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; +import Database from "better-sqlite3"; +import { drizzle } from "drizzle-orm/better-sqlite3"; +import { and, eq } from "drizzle-orm"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { + auditLog, + profile, + schema, + server, + serverMember, + session, + user, +} from "@bb/connect-db"; + +import { + admitServerMember, + handleServerMembersWithDb, + matchServerMembersRoute, +} from "./members.js"; + +const MIGRATIONS_DIR = fileURLToPath( + new URL("../../../packages/connect-db/migrations", import.meta.url), +); +const SECRET = "member-api-test-secret"; +const NOW = new Date("2026-07-18T12:00:00.000Z"); + +let sqlite: Database.Database; +let db: ReturnType; +let sessionOrdinal = 0; + +beforeEach(() => { + sqlite = new Database(":memory:"); + sqlite.pragma("foreign_keys = ON"); + for (const file of readdirSync(MIGRATIONS_DIR).sort()) { + if (!file.endsWith(".sql")) continue; + sqlite.exec(readFileSync(join(MIGRATIONS_DIR, file), "utf8")); + } + db = drizzle(sqlite, { schema }); +}); + +afterEach(() => { + sqlite.close(); +}); + +function seedUser(values: { + id: string; + handle: string; + name?: string; + image?: string | null; +}): void { + db.insert(user) + .values({ + id: values.id, + name: values.name ?? values.id, + email: `${values.id}@example.com`, + emailVerified: true, + image: values.image ?? null, + createdAt: NOW, + updatedAt: NOW, + }) + .run(); + db.insert(profile) + .values({ userId: values.id, handle: values.handle, createdAt: NOW }) + .run(); +} + +function seedServer( + id: string, + ownerUserId: string, + subdomain = "owner", +): void { + db.insert(server) + .values({ + id, + userId: ownerUserId, + name: "default", + subdomain, + credentialHash: "hash", + createdAt: NOW, + }) + .run(); +} + +async function sessionRequest( + userId: string, + url: string, + init: RequestInit = {}, +): Promise { + sessionOrdinal += 1; + const token = `member_session_${sessionOrdinal}_${userId}`; + const key = await crypto.subtle.importKey( + "raw", + new TextEncoder().encode(SECRET), + { name: "HMAC", hash: "SHA-256" }, + false, + ["sign"], + ); + const signature = await crypto.subtle.sign( + "HMAC", + key, + new TextEncoder().encode(token), + ); + const encodedSignature = btoa( + String.fromCharCode(...new Uint8Array(signature)), + ); + db.insert(session) + .values({ + id: `session-${sessionOrdinal}`, + token, + expiresAt: new Date(Date.now() + 60_000), + userId, + createdAt: NOW, + updatedAt: NOW, + }) + .run(); + const headers = new Headers(init.headers); + headers.set( + "cookie", + `__Secure-better-auth.session_token=${encodeURIComponent(`${token}.${encodedSignature}`)}`, + ); + return new Request(url, { ...init, headers }); +} + +function route(serverId: string, memberUserId: string | null = null) { + return { serverId, memberUserId }; +} + +describe("server member route parsing", () => { + it("matches collection and item paths exactly", () => { + expect(matchServerMembersRoute("/api/servers/srv-1/members")).toEqual({ + serverId: "srv-1", + memberUserId: null, + }); + expect( + matchServerMembersRoute("/api/servers/srv-1/members/user%2D2"), + ).toEqual({ serverId: "srv-1", memberUserId: "user-2" }); + expect( + matchServerMembersRoute("/api/servers/srv-1/members/extra/path"), + ).toBeNull(); + }); +}); + +describe("owner member-management API", () => { + beforeEach(() => { + seedUser({ id: "owner-user", handle: "owner", name: "Owner" }); + seedUser({ + id: "member-user", + handle: "invited", + name: "Invited User", + image: "https://example.com/avatar.png", + }); + seedUser({ id: "other-user", handle: "other", name: "Other User" }); + seedServer("server-1", "owner-user"); + }); + + it.each([ + ["GET", null, undefined], + ["POST", null, JSON.stringify({ handle: "invited" })], + ["DELETE", "member-user", undefined], + ] as const)( + "returns 403 when a non-owner session calls %s", + async (method, memberUserId, body) => { + const request = await sessionRequest( + "other-user", + `https://getbb.app/api/servers/server-1/members${memberUserId ? `/${memberUserId}` : ""}`, + { + method, + headers: body ? { "content-type": "application/json" } : undefined, + body, + }, + ); + const response = await handleServerMembersWithDb( + request, + SECRET, + db, + route("server-1", memberUserId), + ); + expect(response.status).toBe(403); + }, + ); + + it("returns 403 without an owner session", async () => { + const response = await handleServerMembersWithDb( + new Request("https://getbb.app/api/servers/server-1/members"), + SECRET, + db, + route("server-1"), + ); + expect(response.status).toBe(403); + }); + + it("adds, lists, and removes a member with owner-attributed audit rows", async () => { + const addRequest = await sessionRequest( + "owner-user", + "https://getbb.app/api/servers/server-1/members", + { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ handle: " INVITED " }), + }, + ); + const added = await handleServerMembersWithDb( + addRequest, + SECRET, + db, + route("server-1"), + ); + expect(added.status).toBe(201); + await expect(added.json()).resolves.toMatchObject({ + userId: "member-user", + handle: "invited", + name: "Invited User", + image: "https://example.com/avatar.png", + addedByUserId: "owner-user", + createdAt: expect.any(Number), + }); + + const listRequest = await sessionRequest( + "owner-user", + "https://getbb.app/api/servers/server-1/members", + ); + const listed = await handleServerMembersWithDb( + listRequest, + SECRET, + db, + route("server-1"), + ); + expect(listed.status).toBe(200); + await expect(listed.json()).resolves.toEqual([ + expect.objectContaining({ + userId: "member-user", + handle: "invited", + addedByUserId: "owner-user", + }), + ]); + + const removeRequest = await sessionRequest( + "owner-user", + "https://getbb.app/api/servers/server-1/members/member-user", + { method: "DELETE" }, + ); + const removed = await handleServerMembersWithDb( + removeRequest, + SECRET, + db, + route("server-1", "member-user"), + ); + expect(removed.status).toBe(204); + expect( + db + .select() + .from(serverMember) + .where(eq(serverMember.serverId, "server-1")) + .all(), + ).toEqual([]); + + const auditRows = db + .select({ + userId: auditLog.userId, + action: auditLog.action, + detail: auditLog.detail, + }) + .from(auditLog) + .all(); + expect(auditRows).toEqual([ + { + userId: "owner-user", + action: "member-added", + detail: JSON.stringify({ + serverId: "server-1", + memberUserId: "member-user", + }), + }, + { + userId: "owner-user", + action: "member-removed", + detail: JSON.stringify({ + serverId: "server-1", + memberUserId: "member-user", + }), + }, + ]); + }); + + it("returns 404 for an unknown handle", async () => { + const request = await sessionRequest( + "owner-user", + "https://getbb.app/api/servers/server-1/members", + { + method: "POST", + body: JSON.stringify({ handle: "missing" }), + }, + ); + const response = await handleServerMembersWithDb( + request, + SECRET, + db, + route("server-1"), + ); + expect(response.status).toBe(404); + }); + + it("returns 409 when the profile is already a member", async () => { + db.insert(serverMember) + .values({ + serverId: "server-1", + userId: "member-user", + addedByUserId: "owner-user", + createdAt: NOW, + }) + .run(); + const request = await sessionRequest( + "owner-user", + "https://getbb.app/api/servers/server-1/members", + { + method: "POST", + body: JSON.stringify({ handle: "invited" }), + }, + ); + const response = await handleServerMembersWithDb( + request, + SECRET, + db, + route("server-1"), + ); + expect(response.status).toBe(409); + }); + + it("returns 400 when the normalized handle belongs to the owner", async () => { + const request = await sessionRequest( + "owner-user", + "https://getbb.app/api/servers/server-1/members", + { + method: "POST", + body: JSON.stringify({ handle: " OWNER " }), + }, + ); + const response = await handleServerMembersWithDb( + request, + SECRET, + db, + route("server-1"), + ); + expect(response.status).toBe(400); + }); + + it("returns 404 when deleting an absent member", async () => { + const request = await sessionRequest( + "owner-user", + "https://getbb.app/api/servers/server-1/members/member-user", + { method: "DELETE" }, + ); + const response = await handleServerMembersWithDb( + request, + SECRET, + db, + route("server-1", "member-user"), + ); + expect(response.status).toBe(404); + }); +}); + +describe("member gate admission audit", () => { + it("admits only a matching member and debounces the durable audit row", async () => { + seedUser({ id: "audit-owner", handle: "audit-owner" }); + seedUser({ id: "audit-member", handle: "audit-member" }); + seedUser({ id: "audit-other", handle: "audit-other" }); + seedServer("audit-server", "audit-owner", "audit-bb"); + db.insert(serverMember) + .values({ + serverId: "audit-server", + userId: "audit-member", + addedByUserId: "audit-owner", + createdAt: NOW, + }) + .run(); + + await expect( + admitServerMember( + db, + "audit-server", + "audit-other", + "audit-bb", + NOW.getTime(), + ), + ).resolves.toBe(false); + await expect( + Promise.all([ + admitServerMember( + db, + "audit-server", + "audit-member", + "audit-bb", + NOW.getTime(), + ), + admitServerMember( + db, + "audit-server", + "audit-member", + "audit-bb", + NOW.getTime(), + ), + ]), + ).resolves.toEqual([true, true]); + await expect( + admitServerMember( + db, + "audit-server", + "audit-member", + "audit-bb", + NOW.getTime() + 14 * 60_000, + ), + ).resolves.toBe(true); + + const rows = db + .select() + .from(auditLog) + .where( + and( + eq(auditLog.action, "member-admitted"), + eq(auditLog.userId, "audit-member"), + ), + ) + .all(); + expect(rows).toHaveLength(1); + expect(rows[0].detail).toBe( + JSON.stringify({ serverId: "audit-server", subdomain: "audit-bb" }), + ); + }); +}); diff --git a/apps/connect/src/members.ts b/apps/connect/src/members.ts new file mode 100644 index 0000000000..e040c233b6 --- /dev/null +++ b/apps/connect/src/members.ts @@ -0,0 +1,379 @@ +import { and, asc, eq } from "drizzle-orm"; +import { drizzle } from "drizzle-orm/d1"; +import { + auditLog, + profile, + schema, + server, + serverMember, + user, + type ConnectDb, +} from "@bb/connect-db"; +import { parseCookie, verifySessionCookie } from "./session.js"; +import type { Env } from "./tunnel-do.js"; + +const SESSION_COOKIE = "__Secure-better-auth.session_token"; +const MEMBER_ADMISSION_AUDIT_WINDOW_MS = 15 * 60 * 1000; + +interface AdmissionAuditState { + lastWrittenAt: number; + pending: Promise | null; +} + +// Per-isolate debounce. A pending write is shared too, so the burst of requests +// from one page load cannot race into a row per asset. Isolate restarts may +// duplicate the entry, which is intentionally acceptable for this audit log. +const memberAdmissionAuditState = new Map(); + +export interface ServerMembersRoute { + serverId: string; + memberUserId: string | null; +} + +export interface ServerMemberListing { + userId: string; + handle: string; + name: string; + image: string | null; + addedByUserId: string; + createdAt: number; +} + +type AddServerMemberResult = + | { ok: true; member: ServerMemberListing } + | { + ok: false; + reason: "already-member" | "cannot-add-owner" | "unknown-handle"; + }; + +function jsonError(error: string, status: number): Response { + return Response.json({ error }, { status }); +} + +function isUniqueConstraintError(error: unknown): boolean { + return error instanceof Error && /unique constraint/iu.test(error.message); +} + +/** Affected-row count from either better-sqlite3 or D1. */ +function affectedRows(result: unknown): number { + if (typeof result === "object" && result !== null) { + if ("changes" in result && typeof result.changes === "number") { + return result.changes; + } + if ( + "meta" in result && + typeof result.meta === "object" && + result.meta !== null && + "changes" in result.meta && + typeof result.meta.changes === "number" + ) { + return result.meta.changes; + } + } + throw new Error("server member mutation did not report affected rows"); +} + +async function appendAuditLog( + db: ConnectDb, + values: { + userId: string; + action: "member-added" | "member-admitted" | "member-removed"; + detail: Record; + createdAt: Date; + }, +): Promise { + await db + .insert(auditLog) + .values({ + id: crypto.randomUUID(), + userId: values.userId, + action: values.action, + detail: JSON.stringify(values.detail), + createdAt: values.createdAt, + }) + .run(); +} + +/** Parse the owner member-management API path before host routing. */ +export function matchServerMembersRoute( + pathname: string, +): ServerMembersRoute | null { + const match = pathname.match( + /^\/api\/servers\/([^/]+)\/members(?:\/([^/]+))?$/u, + ); + if (!match) return null; + try { + return { + serverId: decodeURIComponent(match[1]), + memberUserId: match[2] ? decodeURIComponent(match[2]) : null, + }; + } catch { + return null; + } +} + +/** + * Verify membership and durably record a debounced admission before returning + * true. A failed audit write rejects the request instead of admitting access + * without the system's only verified access record. + */ +export async function admitServerMember( + db: ConnectDb, + serverId: string, + memberUserId: string, + subdomain: string, + now: number = Date.now(), +): Promise { + const membership = await db + .select({ userId: serverMember.userId }) + .from(serverMember) + .where( + and( + eq(serverMember.serverId, serverId), + eq(serverMember.userId, memberUserId), + ), + ) + .get(); + if (!membership) return false; + + const key = `${serverId}:${memberUserId}`; + const current = memberAdmissionAuditState.get(key); + if (current?.pending) { + await current.pending; + return true; + } + if ( + current && + now - current.lastWrittenAt < MEMBER_ADMISSION_AUDIT_WINDOW_MS + ) { + return true; + } + + const pending = appendAuditLog(db, { + userId: memberUserId, + action: "member-admitted", + detail: { serverId, subdomain }, + createdAt: new Date(now), + }); + memberAdmissionAuditState.set(key, { + lastWrittenAt: current?.lastWrittenAt ?? Number.NEGATIVE_INFINITY, + pending, + }); + try { + await pending; + memberAdmissionAuditState.set(key, { lastWrittenAt: now, pending: null }); + } catch (error) { + memberAdmissionAuditState.delete(key); + throw error; + } + return true; +} + +/** Owner-facing member projection, ordered by admission time then handle. */ +export async function listServerMembers( + db: ConnectDb, + serverId: string, +): Promise { + const rows = await db + .select({ + userId: serverMember.userId, + handle: profile.handle, + name: user.name, + image: user.image, + addedByUserId: serverMember.addedByUserId, + createdAt: serverMember.createdAt, + }) + .from(serverMember) + .innerJoin(profile, eq(profile.userId, serverMember.userId)) + .innerJoin(user, eq(user.id, serverMember.userId)) + .where(eq(serverMember.serverId, serverId)) + .orderBy(asc(serverMember.createdAt), asc(profile.handle)) + .all(); + return rows.map((row) => ({ + ...row, + createdAt: row.createdAt.getTime(), + })); +} + +export async function addServerMember( + db: ConnectDb, + serverId: string, + ownerUserId: string, + rawHandle: string, + now: Date = new Date(), +): Promise { + const handle = rawHandle.trim().toLowerCase(); + const target = await db + .select({ + userId: profile.userId, + handle: profile.handle, + name: user.name, + image: user.image, + }) + .from(profile) + .innerJoin(user, eq(user.id, profile.userId)) + .where(eq(profile.handle, handle)) + .get(); + if (!target) return { ok: false, reason: "unknown-handle" }; + if (target.userId === ownerUserId) { + return { ok: false, reason: "cannot-add-owner" }; + } + + try { + await db + .insert(serverMember) + .values({ + serverId, + userId: target.userId, + addedByUserId: ownerUserId, + createdAt: now, + }) + .run(); + } catch (error) { + if (isUniqueConstraintError(error)) { + return { ok: false, reason: "already-member" }; + } + throw error; + } + + await appendAuditLog(db, { + userId: ownerUserId, + action: "member-added", + detail: { serverId, memberUserId: target.userId }, + createdAt: now, + }); + return { + ok: true, + member: { + userId: target.userId, + handle: target.handle, + name: target.name, + image: target.image, + addedByUserId: ownerUserId, + createdAt: now.getTime(), + }, + }; +} + +export async function removeServerMember( + db: ConnectDb, + serverId: string, + ownerUserId: string, + memberUserId: string, + now: Date = new Date(), +): Promise { + const result = await db + .delete(serverMember) + .where( + and( + eq(serverMember.serverId, serverId), + eq(serverMember.userId, memberUserId), + ), + ) + .run(); + if (affectedRows(result) === 0) return false; + + await appendAuditLog(db, { + userId: ownerUserId, + action: "member-removed", + detail: { serverId, memberUserId }, + createdAt: now, + }); + return true; +} + +async function resolveOwnerSessionUserId( + request: Request, + secret: string, + db: ConnectDb, +): Promise { + const cookie = parseCookie(request.headers.get("cookie"), SESSION_COOKIE); + if (!cookie) return null; + return verifySessionCookie(cookie, secret, db); +} + +/** Testable owner-session member API using either D1 or in-memory SQLite. */ +export async function handleServerMembersWithDb( + request: Request, + secret: string, + db: ConnectDb, + route: ServerMembersRoute, +): Promise { + const isCollectionMethod = + route.memberUserId === null && + (request.method === "GET" || request.method === "POST"); + const isItemMethod = + route.memberUserId !== null && request.method === "DELETE"; + if (!isCollectionMethod && !isItemMethod) { + const allow = route.memberUserId === null ? "GET, POST" : "DELETE"; + return new Response(JSON.stringify({ error: "method_not_allowed" }), { + status: 405, + headers: { + "content-type": "application/json; charset=utf-8", + allow, + }, + }); + } + + const sessionUserId = await resolveOwnerSessionUserId(request, secret, db); + if (!sessionUserId) return jsonError("forbidden", 403); + const ownedServer = await db + .select({ id: server.id }) + .from(server) + .where(and(eq(server.id, route.serverId), eq(server.userId, sessionUserId))) + .get(); + if (!ownedServer) return jsonError("forbidden", 403); + + if (request.method === "GET") { + return Response.json(await listServerMembers(db, route.serverId)); + } + + if (request.method === "POST") { + const body: unknown = await request.json().catch(() => null); + if ( + typeof body !== "object" || + body === null || + Array.isArray(body) || + Object.keys(body).length !== 1 || + !("handle" in body) || + typeof body.handle !== "string" + ) { + return jsonError("invalid_request", 400); + } + const result = await addServerMember( + db, + route.serverId, + sessionUserId, + body.handle, + ); + if (!result.ok) { + if (result.reason === "unknown-handle") { + return jsonError("unknown_handle", 404); + } + if (result.reason === "already-member") { + return jsonError("already_member", 409); + } + return jsonError("cannot_add_owner", 400); + } + return Response.json(result.member, { status: 201 }); + } + + const removed = await removeServerMember( + db, + route.serverId, + sessionUserId, + route.memberUserId!, + ); + return removed + ? new Response(null, { status: 204 }) + : jsonError("not_found", 404); +} + +export async function handleServerMembers( + request: Request, + env: Env, + route: ServerMembersRoute, +): Promise { + const db = drizzle(env.DB, { schema }); + return handleServerMembersWithDb(request, env.BETTER_AUTH_SECRET, db, route); +} diff --git a/apps/connect/src/worker.test.ts b/apps/connect/src/worker.test.ts index 596acffee6..66110eee71 100644 --- a/apps/connect/src/worker.test.ts +++ b/apps/connect/src/worker.test.ts @@ -122,6 +122,16 @@ vi.mock("./machine-label.js", () => ({ handleAssignMachineLabel: vi.fn(), })); +vi.mock("./members.js", async () => { + const actual = + await vi.importActual("./members.js"); + return { + ...actual, + admitServerMember: vi.fn(async () => false), + handleServerMembers: vi.fn(), + }; +}); + vi.mock("./cache.js", async () => { const actual = await vi.importActual("./cache.js"); @@ -158,6 +168,7 @@ import { verifyDesktopSessionCookie, } from "./servers.js"; import { handleAssignMachineLabel } from "./machine-label.js"; +import { admitServerMember, handleServerMembers } from "./members.js"; import { serveWithCache } from "./cache.js"; import worker, { offlinePage, relativeTime, wantsHtml } from "./worker.js"; import { TUNNEL_OFFLINE_HEADER, TunnelDO } from "./tunnel-do.js"; @@ -172,6 +183,8 @@ const mockHandleListAccountServers = vi.mocked(handleListAccountServers); const mockHandleCreateDesktopSession = vi.mocked(handleCreateDesktopSession); const mockVerifyDesktopSession = vi.mocked(verifyDesktopSessionCookie); const mockHandleAssignMachineLabel = vi.mocked(handleAssignMachineLabel); +const mockAdmitServerMember = vi.mocked(admitServerMember); +const mockHandleServerMembers = vi.mocked(handleServerMembers); /** A resolved server row; overrides let a test tweak one field. */ function resolvedServer( @@ -354,6 +367,44 @@ describe("POST /api/connect/machine-label", () => { }); }); +describe("/api/servers/:serverId/members", () => { + it("intercepts collection and item routes before host routing", async () => { + mockHandleServerMembers + .mockResolvedValueOnce(Response.json([])) + .mockResolvedValueOnce(new Response(null, { status: 204 })); + const { env, ctx, captured } = makeEnv(() => new Response("origin")); + + const collectionRequest = visitorRequest( + "unknown.getbb.app", + "/api/servers/srv-1/members", + ); + const collection = await worker.fetch(collectionRequest, env as never, ctx); + const itemRequest = visitorRequest( + "unknown.getbb.app", + "/api/servers/srv-1/members/user-2", + { method: "DELETE" }, + ); + const item = await worker.fetch(itemRequest, env as never, ctx); + + expect(collection.status).toBe(200); + expect(item.status).toBe(204); + expect(mockHandleServerMembers).toHaveBeenNthCalledWith( + 1, + collectionRequest, + env, + { serverId: "srv-1", memberUserId: null }, + ); + expect(mockHandleServerMembers).toHaveBeenNthCalledWith( + 2, + itemRequest, + env, + { serverId: "srv-1", memberUserId: "user-2" }, + ); + expect(mockResolveLabel).not.toHaveBeenCalled(); + expect(captured).toHaveLength(0); + }); +}); + describe("gate tunnel authentication", () => { beforeEach(() => { vi.clearAllMocks(); @@ -861,6 +912,45 @@ describe("gate worker share hosts", () => { expect(captured).toHaveLength(0); }); + it("admits a server member session and records the admission before proxying", async () => { + mockVerifySession.mockResolvedValue(OTHER); + mockAdmitServerMember.mockResolvedValueOnce(true); + const { env, ctx, captured } = makeEnv(() => new Response("member-origin")); + const response = await worker.fetch( + visitorRequest("sawyer.getbb.app", "/threads"), + env as never, + ctx, + ); + + expect(response.status).toBe(200); + expect(await response.text()).toBe("member-origin"); + expect(mockAdmitServerMember).toHaveBeenCalledWith( + expect.anything(), + "srv1", + OTHER, + "sawyer", + ); + expect(captured).toHaveLength(1); + }); + + it("does not treat a desktop cookie as member identity", async () => { + mockParseCookie.mockImplementation((_header, name) => + name === DESKTOP_SESSION_COOKIE ? "desktop-token" : null, + ); + mockVerifyDesktopSession.mockResolvedValue(OTHER); + mockAdmitServerMember.mockResolvedValueOnce(true); + const { env, ctx, captured } = makeEnv(() => new Response("origin")); + const response = await worker.fetch( + visitorRequest("sawyer.getbb.app", "/"), + env as never, + ctx, + ); + + expect(response.status).toBe(403); + expect(mockAdmitServerMember).not.toHaveBeenCalled(); + expect(captured).toHaveLength(0); + }); + it("accepts the short-lived desktop cookie for the owning account", async () => { mockParseCookie.mockImplementation((_header, name) => name === DESKTOP_SESSION_COOKIE ? "desktop-token" : null, diff --git a/apps/connect/src/worker.ts b/apps/connect/src/worker.ts index 78512b15ae..376bd42e00 100644 --- a/apps/connect/src/worker.ts +++ b/apps/connect/src/worker.ts @@ -17,6 +17,11 @@ import { import { serveWithCache } from "./cache.js"; import { BB_ICON_DATA_URI } from "./bb-icon.js"; import { handleAssignMachineLabel } from "./machine-label.js"; +import { + admitServerMember, + handleServerMembers, + matchServerMembersRoute, +} from "./members.js"; export { TunnelDO }; @@ -272,6 +277,10 @@ export default { if (url.pathname === "/api/connect/machine-label") { return handleAssignMachineLabel(request, env); } + const serverMembersRoute = matchServerMembersRoute(url.pathname); + if (serverMembersRoute) { + return handleServerMembers(request, env, serverMembersRoute); + } const host = request.headers.get("host") ?? url.host; const parsed = parseVisitorHost(host, env.BASE_DOMAIN); @@ -421,11 +430,14 @@ export default { if (!sessionUserId && !desktopUserId) { return signInPage(label, appUrl, url.toString()); } - if ( - sessionUserId !== resolved.userId && - desktopUserId !== resolved.userId - ) { - return text("bb connect: not your server\n", 403); + const isOwner = + sessionUserId === resolved.userId || desktopUserId === resolved.userId; + if (!isOwner) { + const isMember = + resolved.kind === "server" && + sessionUserId !== null && + (await admitServerMember(db, resolved.server.id, sessionUserId, label)); + if (!isMember) return text("bb connect: not your server\n", 403); } const doRequest = requestForTunnelDo(request, target, "session"); diff --git a/apps/server/src/server.ts b/apps/server/src/server.ts index c6306ed5de..b21fcd13a6 100644 --- a/apps/server/src/server.ts +++ b/apps/server/src/server.ts @@ -71,6 +71,12 @@ import { type PluginCatalogService, } from "./services/plugin-catalog/plugin-catalog-service.js"; import { callHostRetryableOnlineRpc } from "./services/hosts/online-rpc.js"; +import { + createActorService, + createLocalOperatorIdentity, + setRequestActor, +} from "./services/actors.js"; +import { registerSocketActor } from "./ws/socket-actors.js"; export type CloseWebSockets = () => Promise; type NodeWebSocketServer = ReturnType["wss"]; @@ -309,6 +315,11 @@ export function createApp( dataDir: deps.config.dataDir, serverEntryUrl: import.meta.url, }); + const actorService = createActorService({ + db: deps.db, + defaultActor: createLocalOperatorIdentity(), + now: Date.now, + }); app.use("*", async (context, next) => { captureTrustedRemoteAddress(context); @@ -362,6 +373,7 @@ export function createApp( }); }); app.use("/api/v1/*", async (context, next) => { + setRequestActor(context, actorService.resolveRequest(context.req)); const startedAt = performance.now(); await next(); const durationMs = performance.now() - startedAt; @@ -469,12 +481,18 @@ export function createApp( app.get( "/ws", - upgradeWebSocket(() => ({ - onOpen: (_event, socket) => onClientSocketOpen(deps.hub, socket), - onMessage: (event, socket) => - onClientSocketMessage(deps, socket, event.data), - onClose: (_event, socket) => onClientSocketClose(deps, socket), - })), + upgradeWebSocket((context) => { + const actor = actorService.resolveRequest(context.req); + return { + onOpen: (_event, socket) => { + registerSocketActor(socket, actor); + onClientSocketOpen(deps.hub, socket); + }, + onMessage: (event, socket) => + onClientSocketMessage(deps, socket, event.data), + onClose: (_event, socket) => onClientSocketClose(deps, socket), + }; + }), ); app.get( diff --git a/apps/server/src/services/actors.ts b/apps/server/src/services/actors.ts new file mode 100644 index 0000000000..4107ddd75c --- /dev/null +++ b/apps/server/src/services/actors.ts @@ -0,0 +1,118 @@ +import { hostname, userInfo } from "node:os"; +import { upsertCollaborator, type DbConnection } from "@bb/db"; +import { + CLAIMED_IDENTITY_HEADER, + decodeClaimedIdentityHeader, + normalizeHandle, + type ClaimedIdentity, +} from "@bb/domain"; +import type { Context } from "hono"; + +export const REQUEST_ACTOR_CONTEXT_KEY = "bbRequestActor"; +export const COLLABORATOR_WRITE_DEBOUNCE_MS = 60_000; + +interface ClaimedIdentityHeaderReader { + header(name: string): string | undefined; +} + +interface CollaboratorWrite { + displayName: string; + imageUrl: string | null; + writtenAt: number; +} + +export interface ActorService { + resolveRequest(reader: ClaimedIdentityHeaderReader): ClaimedIdentity; +} + +interface CreateActorServiceArgs { + db: DbConnection; + defaultActor: ClaimedIdentity; + now(): number; +} + +declare module "hono" { + interface ContextVariableMap { + [REQUEST_ACTOR_CONTEXT_KEY]: ClaimedIdentity | undefined; + } +} + +export function createLocalOperatorIdentity(): ClaimedIdentity { + let username = ""; + try { + username = userInfo().username.trim(); + } catch { + // Some restricted runtimes cannot resolve the current OS user. + } + const normalizedUsername = normalizeHandle(username); + const localHostname = hostname().trim(); + + return { + handle: normalizedUsername || "local", + displayName: username || localHostname || "local", + imageUrl: null, + clientId: "local", + }; +} + +export function resolveRequestActor( + reader: ClaimedIdentityHeaderReader, + defaultActor: ClaimedIdentity, +): ClaimedIdentity { + return ( + decodeClaimedIdentityHeader(reader.header(CLAIMED_IDENTITY_HEADER)) ?? + defaultActor + ); +} + +export function createActorService(args: CreateActorServiceArgs): ActorService { + const recentWrites = new Map(); + + return { + resolveRequest(reader): ClaimedIdentity { + const actor = resolveRequestActor(reader, args.defaultActor); + const now = args.now(); + const previousWrite = recentWrites.get(actor.handle); + if ( + previousWrite !== undefined && + previousWrite.displayName === actor.displayName && + previousWrite.imageUrl === actor.imageUrl && + now - previousWrite.writtenAt < COLLABORATOR_WRITE_DEBOUNCE_MS + ) { + return actor; + } + + upsertCollaborator( + args.db, + { + handle: actor.handle, + displayName: actor.displayName, + imageUrl: actor.imageUrl, + }, + now, + ); + recentWrites.set(actor.handle, { + displayName: actor.displayName, + imageUrl: actor.imageUrl, + writtenAt: now, + }); + + return actor; + }, + }; +} + +export function setRequestActor( + context: Context, + actor: ClaimedIdentity, +): void { + context.set(REQUEST_ACTOR_CONTEXT_KEY, actor); +} + +export function getRequestActor(context: Context): ClaimedIdentity { + const actor = context.get(REQUEST_ACTOR_CONTEXT_KEY); + if (actor === undefined) { + throw new Error("Request actor has not been resolved"); + } + return actor; +} diff --git a/apps/server/src/ws/client-protocol.ts b/apps/server/src/ws/client-protocol.ts index dd110d068d..dd7cdb6c2b 100644 --- a/apps/server/src/ws/client-protocol.ts +++ b/apps/server/src/ws/client-protocol.ts @@ -1,6 +1,7 @@ import { clientMessageSchema } from "@bb/domain"; import { decodeSocketPayload } from "./decode-payload.js"; import type { NotificationHub } from "./hub.js"; +import { releaseSocketActor } from "./socket-actors.js"; import type { WatchInterestCoordinator } from "./watch-interests.js"; interface ClientSocket { @@ -69,6 +70,7 @@ export function onClientSocketClose( }, socket: ClientSocket, ): void { + releaseSocketActor(socket); deps.watchInterests.releaseSocket(socket); deps.hub.unregisterClient(socket); } diff --git a/apps/server/src/ws/socket-actors.ts b/apps/server/src/ws/socket-actors.ts new file mode 100644 index 0000000000..53a61306ed --- /dev/null +++ b/apps/server/src/ws/socket-actors.ts @@ -0,0 +1,18 @@ +import type { ClaimedIdentity } from "@bb/domain"; + +const socketActors = new WeakMap(); + +export function registerSocketActor( + socket: object, + actor: ClaimedIdentity, +): void { + socketActors.set(socket, actor); +} + +export function releaseSocketActor(socket: object): void { + socketActors.delete(socket); +} + +export function getSocketActor(socket: object): ClaimedIdentity | null { + return socketActors.get(socket) ?? null; +} diff --git a/apps/server/test/app/client-protocol.test.ts b/apps/server/test/app/client-protocol.test.ts index b297d912ac..8a6bbb5866 100644 --- a/apps/server/test/app/client-protocol.test.ts +++ b/apps/server/test/app/client-protocol.test.ts @@ -1,9 +1,14 @@ import { describe, expect, it, vi } from "vitest"; import { + onClientSocketClose, onClientSocketMessage, onClientSocketOpen, } from "../../src/ws/client-protocol.js"; import { NotificationHub } from "../../src/ws/hub.js"; +import { + getSocketActor, + registerSocketActor, +} from "../../src/ws/socket-actors.js"; import { createMockHubSocket } from "../helpers/mock-hub-socket.js"; function createProtocolDeps(hub: NotificationHub) { @@ -194,4 +199,23 @@ describe("client websocket protocol", () => { expect(socket.closed).toEqual([{ code: 1008, reason: "invalid-message" }]); expect(deps.watchInterests.subscribe).not.toHaveBeenCalled(); }); + + it("releases the socket actor when the client socket closes", () => { + const hub = new NotificationHub(); + const deps = createProtocolDeps(hub); + const socket = createMockHubSocket(); + const actor = { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + clientId: "browser-1", + }; + + onClientSocketOpen(hub, socket); + registerSocketActor(socket, actor); + onClientSocketClose(deps, socket); + + expect(getSocketActor(socket)).toBeNull(); + expect(deps.watchInterests.releaseSocket).toHaveBeenCalledWith(socket); + }); }); diff --git a/apps/server/test/app/socket-actors.test.ts b/apps/server/test/app/socket-actors.test.ts new file mode 100644 index 0000000000..528fe89d0d --- /dev/null +++ b/apps/server/test/app/socket-actors.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from "vitest"; +import type { ClaimedIdentity } from "@bb/domain"; +import { + getSocketActor, + registerSocketActor, + releaseSocketActor, +} from "../../src/ws/socket-actors.js"; + +const actor: ClaimedIdentity = { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + clientId: "browser-1", +}; + +describe("socket actors", () => { + it("registers and releases a socket actor", () => { + const socket = {}; + + expect(getSocketActor(socket)).toBeNull(); + registerSocketActor(socket, actor); + expect(getSocketActor(socket)).toBe(actor); + releaseSocketActor(socket); + expect(getSocketActor(socket)).toBeNull(); + }); +}); diff --git a/apps/server/test/public/public-request-actors.test.ts b/apps/server/test/public/public-request-actors.test.ts new file mode 100644 index 0000000000..e2f9552014 --- /dev/null +++ b/apps/server/test/public/public-request-actors.test.ts @@ -0,0 +1,78 @@ +import { describe, expect, it } from "vitest"; +import { listCollaborators } from "@bb/db"; +import { + CLAIMED_IDENTITY_HEADER, + encodeClaimedIdentityHeader, +} from "@bb/domain"; +import { createLocalOperatorIdentity } from "../../src/services/actors.js"; +import { withTestHarness } from "../helpers/test-app.js"; + +describe("public request actors", () => { + it("records the valid claimed identity resolved for an API request", async () => { + await withTestHarness(async (harness) => { + const response = await harness.app.request("/api/v1/does-not-exist", { + headers: { + [CLAIMED_IDENTITY_HEADER]: encodeClaimedIdentityHeader({ + handle: "Sawyer", + displayName: "Sawyer Hood", + imageUrl: null, + clientId: "browser-1", + }), + }, + }); + + expect(response.status).toBe(404); + expect(listCollaborators(harness.db)).toEqual([ + { + handle: "sawyer", + displayName: "Sawyer Hood", + imageUrl: null, + firstSeenAt: expect.any(Number), + lastSeenAt: expect.any(Number), + }, + ]); + }); + }); + + it("records the local operator when the claimed identity is malformed", async () => { + await withTestHarness(async (harness) => { + const response = await harness.app.request("/api/v1/does-not-exist", { + headers: { + [CLAIMED_IDENTITY_HEADER]: "malformed", + }, + }); + + expect(response.status).toBe(404); + const localOperator = createLocalOperatorIdentity(); + expect(listCollaborators(harness.db)).toEqual([ + { + handle: localOperator.handle, + displayName: localOperator.displayName, + imageUrl: null, + firstSeenAt: expect.any(Number), + lastSeenAt: expect.any(Number), + }, + ]); + }); + }); + + it("collapses equivalent normalized handles into one collaborator", async () => { + await withTestHarness(async (harness) => { + for (const handle of ["Sawyer ", "sawyer"]) { + await harness.app.request("/api/v1/does-not-exist", { + headers: { + [CLAIMED_IDENTITY_HEADER]: encodeClaimedIdentityHeader({ + handle, + displayName: "Sawyer", + imageUrl: null, + clientId: "browser-1", + }), + }, + }); + } + + expect(listCollaborators(harness.db)).toHaveLength(1); + expect(listCollaborators(harness.db)[0]?.handle).toBe("sawyer"); + }); + }); +}); diff --git a/apps/server/test/services/actors.test.ts b/apps/server/test/services/actors.test.ts new file mode 100644 index 0000000000..45c6949049 --- /dev/null +++ b/apps/server/test/services/actors.test.ts @@ -0,0 +1,92 @@ +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { + createConnection, + getCollaborator, + migrate, + type DbConnection, +} from "@bb/db"; +import { + CLAIMED_IDENTITY_HEADER, + encodeClaimedIdentityHeader, + type ClaimedIdentity, +} from "@bb/domain"; +import { + createActorService, + resolveRequestActor, +} from "../../src/services/actors.js"; + +const defaultActor: ClaimedIdentity = { + handle: "local", + displayName: "Local Operator", + imageUrl: null, + clientId: "local", +}; + +function headerReader(value: string | undefined) { + return { + header(name: string): string | undefined { + return name === CLAIMED_IDENTITY_HEADER ? value : undefined; + }, + }; +} + +describe("request actors", () => { + let db: DbConnection; + + beforeEach(() => { + db = createConnection(":memory:"); + migrate(db); + }); + + afterEach(() => { + db.$client.close(); + }); + + it("resolves and normalizes a valid claimed identity header", () => { + const encoded = encodeClaimedIdentityHeader({ + handle: " Sawyer ", + displayName: "Sawyer", + imageUrl: "https://example.test/avatar.png", + clientId: "browser-1", + }); + + expect(resolveRequestActor(headerReader(encoded), defaultActor)).toEqual({ + handle: "sawyer", + displayName: "Sawyer", + imageUrl: "https://example.test/avatar.png", + clientId: "browser-1", + }); + }); + + it("falls back to the local operator for a malformed header", () => { + expect( + resolveRequestActor(headerReader("not-valid-encoded-json"), defaultActor), + ).toBe(defaultActor); + }); + + it("skips unchanged collaborator writes within the debounce window", () => { + let now = 1_000; + const actorService = createActorService({ + db, + defaultActor, + now: () => now, + }); + const encoded = encodeClaimedIdentityHeader({ + handle: "Sawyer", + displayName: "Sawyer", + imageUrl: null, + clientId: "browser-1", + }); + + actorService.resolveRequest(headerReader(encoded)); + now = 2_000; + actorService.resolveRequest(headerReader(encoded)); + + expect(getCollaborator(db, "sawyer")?.lastSeenAt).toBe(1_000); + + now = 61_000; + actorService.resolveRequest(headerReader(encoded)); + + expect(getCollaborator(db, "sawyer")?.lastSeenAt).toBe(61_000); + }); +}); diff --git a/packages/db/src/data/collaborators.ts b/packages/db/src/data/collaborators.ts new file mode 100644 index 0000000000..ab5ada4245 --- /dev/null +++ b/packages/db/src/data/collaborators.ts @@ -0,0 +1,54 @@ +import { eq } from "drizzle-orm"; +import type { DbConnection } from "../connection.js"; +import { collaborators } from "../schema.js"; + +export interface UpsertCollaboratorInput { + handle: string; + displayName: string; + imageUrl: string | null; +} + +export type CollaboratorRow = typeof collaborators.$inferSelect; + +export function upsertCollaborator( + db: DbConnection, + input: UpsertCollaboratorInput, + now: number, +): CollaboratorRow { + return db + .insert(collaborators) + .values({ + handle: input.handle, + displayName: input.displayName, + imageUrl: input.imageUrl, + firstSeenAt: now, + lastSeenAt: now, + }) + .onConflictDoUpdate({ + target: collaborators.handle, + set: { + displayName: input.displayName, + imageUrl: input.imageUrl, + lastSeenAt: now, + }, + }) + .returning() + .get(); +} + +export function getCollaborator( + db: DbConnection, + handle: string, +): CollaboratorRow | null { + return ( + db + .select() + .from(collaborators) + .where(eq(collaborators.handle, handle)) + .get() ?? null + ); +} + +export function listCollaborators(db: DbConnection): CollaboratorRow[] { + return db.select().from(collaborators).all(); +} diff --git a/packages/db/src/data/index.ts b/packages/db/src/data/index.ts index 2e5961679e..2d12bdda82 100644 --- a/packages/db/src/data/index.ts +++ b/packages/db/src/data/index.ts @@ -562,3 +562,13 @@ export type { DropDeferredLegacyTablesResult, RunIncrementalVacuumArgs, } from "./maintenance.js"; + +export { + getCollaborator, + listCollaborators, + upsertCollaborator, +} from "./collaborators.js"; +export type { + CollaboratorRow, + UpsertCollaboratorInput, +} from "./collaborators.js"; diff --git a/packages/db/test/data/collaborators.test.ts b/packages/db/test/data/collaborators.test.ts new file mode 100644 index 0000000000..9d84de73ff --- /dev/null +++ b/packages/db/test/data/collaborators.test.ts @@ -0,0 +1,74 @@ +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { + createConnection, + getCollaborator, + listCollaborators, + migrate, + upsertCollaborator, + type DbConnection, +} from "../../src/index.js"; + +describe("collaborators data", () => { + let db: DbConnection; + + beforeEach(() => { + db = createConnection(":memory:"); + migrate(db); + }); + + afterEach(() => { + db.$client.close(); + }); + + it("inserts a collaborator with matching first and last seen timestamps", () => { + const collaborator = upsertCollaborator( + db, + { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + }, + 1_000, + ); + + expect(collaborator).toEqual({ + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + firstSeenAt: 1_000, + lastSeenAt: 1_000, + }); + expect(getCollaborator(db, "sawyer")).toEqual(collaborator); + }); + + it("updates display fields and last seen while preserving first seen", () => { + upsertCollaborator( + db, + { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + }, + 1_000, + ); + + const updated = upsertCollaborator( + db, + { + handle: "sawyer", + displayName: "Sawyer Hood", + imageUrl: "https://example.test/sawyer.png", + }, + 2_000, + ); + + expect(updated).toEqual({ + handle: "sawyer", + displayName: "Sawyer Hood", + imageUrl: "https://example.test/sawyer.png", + firstSeenAt: 1_000, + lastSeenAt: 2_000, + }); + expect(listCollaborators(db)).toEqual([updated]); + }); +}); From 03c7cd9e6cd0802c977bfe8fae9d2807139312d5 Mon Sep 17 00:00:00 2001 From: Sawyer Hood Date: Sat, 18 Jul 2026 09:35:48 -0700 Subject: [PATCH 3/8] Multiplayer wave 2: end-to-end attribution and hub-derived presence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WS3 (attribution): the human request path records its actor everywhere — events.actor_handle on sends (queued messages carry actor_handle and preserve it through every drain path), threads.created_by_handle on human creates, the acting handle on manual-stop interruption events, and pending_interactions.resolved_by_handle on approval resolution. Actors come only from the request-scoped identity, never from request bodies; agent/thread/plugin-origin writes stay NULL. Turn commands gain an optional speaker {handle, displayName}, populated only when the thread has two or more distinct human authors (targeted countDistinct query), and the host daemon prefixes provider input with "[from @handle] " — single-human threads produce byte-identical provider input. HOST_DAEMON_PROTOCOL_VERSION 58 -> 59. WS4 (presence): ephemeral presence derived from thread-detail subscriptions — viewers deduped by handle with per-socket refcounts, typing with a 6s TTL via the ws typing message, strict-schema thread-presence broadcasts to detail subscribers and partial presence-summary patches to thread-list subscribers (empty array removes an entry; no-op rebroadcasts suppressed), plus a GET /api/v1/presence snapshot route. Nothing persisted. Includes the regenerated @bb/plugin-sdk bundled types. Co-Authored-By: Claude Fable 5 --- .../src/command-handlers/thread.test.ts | 35 +++ .../src/command-handlers/thread.ts | 77 +++++- apps/server/src/routes/presence.ts | 23 ++ apps/server/src/routes/threads/actions.ts | 16 +- apps/server/src/routes/threads/base.ts | 7 +- .../server/src/routes/threads/interactions.ts | 24 +- apps/server/src/server.ts | 2 + apps/server/src/services/presence.ts | 195 ++++++++++++++ .../src/services/threads/queued-messages.ts | 8 + .../src/services/threads/thread-commands.ts | 39 +++ .../services/threads/thread-create-helpers.ts | 1 + .../services/threads/thread-create-request.ts | 1 + .../src/services/threads/thread-create.ts | 8 + .../src/services/threads/thread-events.ts | 7 + .../src/services/threads/thread-lifecycle.ts | 11 +- .../threads/thread-provisioning-context.ts | 5 + .../services/threads/thread-provisioning.ts | 7 + .../src/services/threads/thread-send.ts | 11 + .../services/threads/thread-turn-dispatch.ts | 2 + apps/server/src/ws/client-protocol.ts | 6 +- apps/server/src/ws/hub.ts | 110 +++++++- apps/server/test/app/presence.test.ts | 244 ++++++++++++++++++ .../test/public/public-presence.test.ts | 41 +++ .../test/public/public-thread-data.test.ts | 94 ++++++- .../public/public-thread-interactions.test.ts | 24 +- .../public-threads.project-default.test.ts | 65 ++++- .../services/threads/thread-speaker.test.ts | 84 ++++++ packages/db/src/data/events.ts | 34 ++- packages/db/src/data/index.ts | 2 + packages/db/src/data/pending-interactions.ts | 24 +- .../db/src/data/queued-thread-messages.ts | 3 + packages/db/src/data/threads.ts | 2 + packages/db/test/data/events.test.ts | 46 ++++ .../db/test/data/pending-interactions.test.ts | 13 + .../test/data/queued-thread-messages.test.ts | 2 + packages/db/test/data/threads.test.ts | 12 + packages/host-daemon-contract/src/commands.ts | 12 +- .../test/contract.test.ts | 4 +- .../bundled-types/bb-plugin-sdk.d.ts | 22 +- packages/server-contract/src/api-types.ts | 1 + packages/server-contract/src/api/presence.ts | 19 ++ packages/server-contract/src/index.ts | 8 + packages/server-contract/src/public-api.ts | 10 + .../server-contract/test/presence.test.ts | 69 +++++ 44 files changed, 1370 insertions(+), 60 deletions(-) create mode 100644 apps/host-daemon/src/command-handlers/thread.test.ts create mode 100644 apps/server/src/routes/presence.ts create mode 100644 apps/server/src/services/presence.ts create mode 100644 apps/server/test/app/presence.test.ts create mode 100644 apps/server/test/public/public-presence.test.ts create mode 100644 apps/server/test/services/threads/thread-speaker.test.ts create mode 100644 packages/server-contract/src/api/presence.ts create mode 100644 packages/server-contract/test/presence.test.ts diff --git a/apps/host-daemon/src/command-handlers/thread.test.ts b/apps/host-daemon/src/command-handlers/thread.test.ts new file mode 100644 index 0000000000..0ec53a4cd3 --- /dev/null +++ b/apps/host-daemon/src/command-handlers/thread.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from "vitest"; +import { annotateSpeakerInput } from "./thread.js"; + +describe("thread speaker annotation", () => { + it("prefixes the first text input with the speaker handle", () => { + expect( + annotateSpeakerInput( + [ + { type: "text", text: "hello", mentions: [] }, + { type: "text", text: "world", mentions: [] }, + ], + { displayName: "Alice", handle: "alice" }, + ), + ).toEqual([ + { type: "text", text: "[from @alice] hello", mentions: [] }, + { type: "text", text: "world", mentions: [] }, + ]); + }); + + it("adds a text input when the prompt starts with an attachment", () => { + const attachment = { + type: "localImage" as const, + path: "/tmp/image.png", + }; + expect( + annotateSpeakerInput([attachment], { + displayName: "Alice", + handle: "alice", + }), + ).toEqual([ + { type: "text", text: "[from @alice] ", mentions: [] }, + attachment, + ]); + }); +}); diff --git a/apps/host-daemon/src/command-handlers/thread.ts b/apps/host-daemon/src/command-handlers/thread.ts index 164eb02530..fe9cda20ca 100644 --- a/apps/host-daemon/src/command-handlers/thread.ts +++ b/apps/host-daemon/src/command-handlers/thread.ts @@ -1,6 +1,7 @@ import fs from "node:fs/promises"; import type { PromptInput } from "@bb/domain"; import type { HostDaemonCommandResult } from "@bb/host-daemon-contract"; +import type { TurnSpeaker } from "@bb/host-daemon-contract"; import { resolveContainedPath } from "@bb/process-utils"; import type { RuntimeEntry } from "../runtime-manager.js"; import { @@ -26,7 +27,7 @@ interface ResumeThreadRuntimeIfMissingArgs { interface StageThreadCommandInputArgs { command: Pick< TurnSubmitCommand, - "input" | "inputGroups" | "requestId" | "threadId" + "input" | "inputGroups" | "requestId" | "speaker" | "threadId" >; fetchProjectAttachment: CommandDispatchOptions["fetchProjectAttachment"]; projectId: string; @@ -84,6 +85,50 @@ function groupedInputForRuntime( ); } +export function annotateSpeakerInput( + input: readonly PromptInput[], + speaker: TurnSpeaker, +): PromptInput[] { + const annotation = `[from @${speaker.handle}] `; + const firstTextIndex = input.findIndex((item) => item.type === "text"); + if (firstTextIndex === -1) { + return [{ type: "text", text: annotation, mentions: [] }, ...input]; + } + return input.map((item, index) => + index === firstTextIndex && item.type === "text" + ? { ...item, text: `${annotation}${item.text}` } + : item, + ); +} + +function annotateStagedSpeaker( + staged: StagedThreadCommandInput, + speaker: TurnSpeaker | undefined, +): StagedThreadCommandInput { + if (speaker === undefined) { + return staged; + } + if (staged.inputGroups !== undefined) { + const [firstGroup, ...remainingGroups] = staged.inputGroups; + if (firstGroup === undefined) { + return staged; + } + const inputGroups = [ + annotateSpeakerInput(firstGroup, speaker), + ...remainingGroups, + ]; + return { + ...staged, + input: groupedInputForRuntime(inputGroups), + inputGroups, + }; + } + return { + ...staged, + input: annotateSpeakerInput(staged.input, speaker), + }; +} + async function requireSupportedProviderCliForThreadStart({ command, options, @@ -192,12 +237,15 @@ export async function startThread( ); await fs.mkdir(confined, { recursive: true }); } - const staged = await stageThreadCommandInput({ - command, - fetchProjectAttachment: options.fetchProjectAttachment, - projectId: command.projectId, - threadStorageRootPath: options.threadStorageRootPath, - }); + const staged = annotateStagedSpeaker( + await stageThreadCommandInput({ + command, + fetchProjectAttachment: options.fetchProjectAttachment, + projectId: command.projectId, + threadStorageRootPath: options.threadStorageRootPath, + }), + command.speaker, + ); try { const entry = await requireResolvedWorkspaceForCommand({ dataDir: options.dataDir, @@ -306,12 +354,15 @@ export async function submitTurn( entry: RuntimeEntry, options: CommandDispatchOptions, ): Promise> { - const staged = await stageThreadCommandInput({ - command, - fetchProjectAttachment: options.fetchProjectAttachment, - projectId: command.resumeContext.projectId, - threadStorageRootPath: options.threadStorageRootPath, - }); + const staged = annotateStagedSpeaker( + await stageThreadCommandInput({ + command, + fetchProjectAttachment: options.fetchProjectAttachment, + projectId: command.resumeContext.projectId, + threadStorageRootPath: options.threadStorageRootPath, + }), + command.speaker, + ); const stagedCommand = { ...command, input: staged.input, diff --git a/apps/server/src/routes/presence.ts b/apps/server/src/routes/presence.ts new file mode 100644 index 0000000000..04987031ba --- /dev/null +++ b/apps/server/src/routes/presence.ts @@ -0,0 +1,23 @@ +import { + presenceSnapshotResponseSchema, + publicApiRoutes, + typedRoutes, + type PublicApiSchema, +} from "@bb/server-contract"; +import type { Hono } from "hono"; +import { ApiError } from "../errors.js"; +import type { AppDeps } from "../types.js"; + +export function registerPresenceRoutes(app: Hono, deps: AppDeps): void { + const { get } = typedRoutes(app, { + onValidationError: (message) => + new ApiError(400, "invalid_request", message), + }); + + get(publicApiRoutes.presence.snapshot, (context) => { + const snapshot = presenceSnapshotResponseSchema.parse( + deps.hub.getPresenceSnapshot(), + ); + return context.json(snapshot); + }); +} diff --git a/apps/server/src/routes/threads/actions.ts b/apps/server/src/routes/threads/actions.ts index 281bb28c87..dcec9a539b 100644 --- a/apps/server/src/routes/threads/actions.ts +++ b/apps/server/src/routes/threads/actions.ts @@ -24,10 +24,11 @@ import { type PublicApiSchema, type SendMessageRequest, } from "@bb/server-contract"; -import type { Hono } from "hono"; +import type { Context, Hono } from "hono"; import type { Thread, ThreadQueuedMessage } from "@bb/domain"; import type { AppDeps } from "../../types.js"; import { ApiError } from "../../errors.js"; +import { getRequestActor } from "../../services/actors.js"; import { toThreadQueuedMessage } from "../../services/threads/thread-queued-messages.js"; import { requestEnvironmentCleanup, @@ -177,6 +178,7 @@ function assertPinnedThreadOrderResult( } interface CreateQueuedMessageForThreadArgs { + actorHandle: string; payload: CreateQueuedMessageRequest; thread: Thread; } @@ -229,6 +231,7 @@ async function createQueuedMessageForThread( targetThread: thread, }); const queuedMessage = createQueuedThreadMessage(deps.db, deps.hub, { + actorHandle: senderThreadId === null ? args.actorHandle : null, threadId: thread.id, content: payload.input, senderThreadId, @@ -267,9 +270,11 @@ export function registerThreadActionRoutes(app: Hono, deps: AppDeps): void { post(routes.send, async (context, payload) => { const thread = requirePublicThread(deps.db, context.req.param("id")); + const actor = getRequestActor(context as unknown as Context); if (payload.mode === "queue-if-active" && thread.status === "active") { ensureThreadIsNotAwaitingUserInteraction(deps, thread.id); await createQueuedMessageForThread(deps, { + actorHandle: actor.handle, payload: queuedMessagePayloadFromSendRequest(payload), thread, }); @@ -279,6 +284,7 @@ export function registerThreadActionRoutes(app: Hono, deps: AppDeps): void { thread, }); await sendThreadMessage(deps, { + actorHandle: actor.handle, environment, payload, thread, @@ -290,6 +296,7 @@ export function registerThreadActionRoutes(app: Hono, deps: AppDeps): void { post(routes.createQueuedMessage, async (context, payload) => { const thread = requirePublicThread(deps.db, context.req.param("id")); const queuedMessage = await createQueuedMessageForThread(deps, { + actorHandle: getRequestActor(context as unknown as Context).handle, payload, thread, }); @@ -405,7 +412,12 @@ export function registerThreadActionRoutes(app: Hono, deps: AppDeps): void { db: deps.db, thread, }); - requestThreadStopForCurrentState(deps, thread, environment); + requestThreadStopForCurrentState( + deps, + thread, + environment, + getRequestActor(context as unknown as Context).handle, + ); return context.json({ ok: true }); }); diff --git a/apps/server/src/routes/threads/base.ts b/apps/server/src/routes/threads/base.ts index 747f614903..89c82b7bbf 100644 --- a/apps/server/src/routes/threads/base.ts +++ b/apps/server/src/routes/threads/base.ts @@ -23,9 +23,10 @@ import { type ThreadWithIncludesResponse, type PublicApiSchema, } from "@bb/server-contract"; -import type { Hono } from "hono"; +import type { Context, Hono } from "hono"; import type { AppDeps } from "../../types.js"; import { ApiError } from "../../errors.js"; +import { getRequestActor } from "../../services/actors.js"; import { parseOptionalInteger } from "../../services/lib/validation.js"; import { requestEnvironmentCleanup, @@ -263,6 +264,10 @@ export function registerThreadBaseRoutes(app: Hono, deps: AppDeps): void { } const thread = await createThreadFromRequest(deps, { ...payload, + createdByHandle: + payload.origin === "plugin" + ? null + : getRequestActor(context as unknown as Context).handle, origin: payload.origin, }); return context.json(toThreadResponseFromThread(deps, { thread }), 201); diff --git a/apps/server/src/routes/threads/interactions.ts b/apps/server/src/routes/threads/interactions.ts index e9508d474a..eecbf2afed 100644 --- a/apps/server/src/routes/threads/interactions.ts +++ b/apps/server/src/routes/threads/interactions.ts @@ -3,11 +3,13 @@ import { typedRoutes, type PublicApiSchema, } from "@bb/server-contract"; -import type { Hono } from "hono"; +import type { Context, Hono } from "hono"; +import { setPendingInteractionResolvedByHandle } from "@bb/db"; import { z } from "zod"; import type { AppDeps } from "../../types.js"; import { ApiError } from "../../errors.js"; import { requirePublicThread } from "../../services/lib/entity-lookup.js"; +import { getRequestActor } from "../../services/actors.js"; const pendingInteractionIdSchema = z .string() @@ -56,15 +58,19 @@ export function registerThreadInteractionRoutes( post(routes.resolveInteraction, (context, payload) => { const thread = requirePublicThread(deps.db, context.req.param("id")); - return context.json( - deps.pendingInteractions.resolvePendingInteraction({ - threadId: thread.id, - interactionId: parsePendingInteractionId( - context.req.param("interactionId"), - ), - resolution: payload, - }), + const interactionId = parsePendingInteractionId( + context.req.param("interactionId"), ); + const interaction = deps.pendingInteractions.resolvePendingInteraction({ + threadId: thread.id, + interactionId, + resolution: payload, + }); + setPendingInteractionResolvedByHandle(deps.db, { + id: interactionId, + resolvedByHandle: getRequestActor(context as unknown as Context).handle, + }); + return context.json(interaction); }); post(routes.respondToInteraction, (context, payload) => { diff --git a/apps/server/src/server.ts b/apps/server/src/server.ts index b21fcd13a6..2ae60cb36a 100644 --- a/apps/server/src/server.ts +++ b/apps/server/src/server.ts @@ -16,6 +16,7 @@ import { ApiError, errorToResponse } from "./errors.js"; import { registerEnvironmentRoutes } from "./routes/environments.js"; import { registerFileRoutes } from "./routes/files.js"; import { registerHostRoutes } from "./routes/hosts.js"; +import { registerPresenceRoutes } from "./routes/presence.js"; import { registerProjectRoutes } from "./routes/projects.js"; import { registerThreadSectionRoutes } from "./routes/thread-sections.js"; import { registerSystemRoutes } from "./routes/system.js"; @@ -462,6 +463,7 @@ export function createApp( registerTerminalRoutes(publicApi, deps); registerEnvironmentRoutes(publicApi, deps); registerThreadRoutes(publicApi, deps); + registerPresenceRoutes(publicApi, deps); registerSystemRoutes(publicApi, deps, pluginService); registerPluginCatalogRoutes(publicApi, pluginCatalogService); registerPluginRoutes(publicApi, deps, pluginService); diff --git a/apps/server/src/services/presence.ts b/apps/server/src/services/presence.ts new file mode 100644 index 0000000000..9e3ac7c9bc --- /dev/null +++ b/apps/server/src/services/presence.ts @@ -0,0 +1,195 @@ +import type { ClaimedIdentity, PresenceViewer } from "@bb/domain"; +import { getSocketActor } from "../ws/socket-actors.js"; + +export const PRESENCE_TYPING_TTL_MS = 6_000; + +interface ViewerState { + actorsBySocket: Map; + typing: boolean; + typingTimeout: ReturnType | null; +} + +interface PresenceServiceArgs { + onThreadChanged(threadId: string, viewers: readonly PresenceViewer[]): void; + typingTtlMs?: number; +} + +export interface PresenceSnapshot { + threads: Record; +} + +export type PresenceSubscriptionResult = "changed" | "ignored" | "unchanged"; + +/** + * Ephemeral presence derived from thread-detail subscriptions. The service + * retains one entry per handle and reference-counts that handle's sockets, so + * multiple tabs or devices still render as one viewer. + */ +export class PresenceService { + private readonly handlesByThreadBySocket = new WeakMap< + object, + Map + >(); + private readonly lastEmittedRosterByThread = new Map(); + private readonly onThreadChanged: PresenceServiceArgs["onThreadChanged"]; + private readonly typingTtlMs: number; + private readonly viewersByThread = new Map< + string, + Map + >(); + + constructor(args: PresenceServiceArgs) { + this.onThreadChanged = args.onThreadChanged; + this.typingTtlMs = args.typingTtlMs ?? PRESENCE_TYPING_TTL_MS; + } + + subscribe(threadId: string, socket: object): PresenceSubscriptionResult { + const actor = getSocketActor(socket); + if (actor === null) { + return "ignored"; + } + + const handlesByThread = + this.handlesByThreadBySocket.get(socket) ?? new Map(); + if (handlesByThread.has(threadId)) { + return "ignored"; + } + handlesByThread.set(threadId, actor.handle); + this.handlesByThreadBySocket.set(socket, handlesByThread); + + const viewers = + this.viewersByThread.get(threadId) ?? new Map(); + const viewer = viewers.get(actor.handle) ?? { + actorsBySocket: new Map(), + typing: false, + typingTimeout: null, + }; + viewer.actorsBySocket.set(socket, actor); + viewers.set(actor.handle, viewer); + this.viewersByThread.set(threadId, viewers); + return this.emitIfChanged(threadId) ? "changed" : "unchanged"; + } + + unsubscribe(threadId: string, socket: object): void { + const handlesByThread = this.handlesByThreadBySocket.get(socket); + if (handlesByThread === undefined) { + return; + } + const handle = handlesByThread.get(threadId); + if (handle === undefined) { + return; + } + handlesByThread.delete(threadId); + if (handlesByThread.size === 0) { + this.handlesByThreadBySocket.delete(socket); + } + + const viewers = this.viewersByThread.get(threadId); + const viewer = viewers?.get(handle); + if (viewer === undefined || viewers === undefined) { + return; + } + viewer.actorsBySocket.delete(socket); + if (viewer.actorsBySocket.size === 0) { + this.clearTypingTimeout(viewer); + viewers.delete(handle); + } + if (viewers.size === 0) { + this.viewersByThread.delete(threadId); + } + this.emitIfChanged(threadId); + } + + setTyping(socket: object, threadId: string, typing: boolean): void { + const handle = this.handlesByThreadBySocket.get(socket)?.get(threadId); + if (handle === undefined) { + return; + } + const viewer = this.viewersByThread.get(threadId)?.get(handle); + if (viewer === undefined) { + return; + } + + this.clearTypingTimeout(viewer); + if (!typing) { + if (viewer.typing) { + viewer.typing = false; + this.emitIfChanged(threadId); + } + return; + } + + const wasTyping = viewer.typing; + viewer.typing = true; + viewer.typingTimeout = setTimeout(() => { + viewer.typingTimeout = null; + if (!viewer.typing) { + return; + } + viewer.typing = false; + this.emitIfChanged(threadId); + }, this.typingTtlMs); + viewer.typingTimeout.unref(); + + if (!wasTyping) { + this.emitIfChanged(threadId); + } + } + + snapshot(): PresenceSnapshot { + const threads: Record = {}; + for (const threadId of [...this.viewersByThread.keys()].sort()) { + const viewers = this.rosterForThread(threadId); + if (viewers.length > 0) { + threads[threadId] = viewers; + } + } + return { threads }; + } + + private clearTypingTimeout(viewer: ViewerState): void { + if (viewer.typingTimeout === null) { + return; + } + clearTimeout(viewer.typingTimeout); + viewer.typingTimeout = null; + } + + private emitIfChanged(threadId: string): boolean { + const roster = this.rosterForThread(threadId); + const serialized = JSON.stringify(roster); + if (this.lastEmittedRosterByThread.get(threadId) === serialized) { + return false; + } + this.lastEmittedRosterByThread.set(threadId, serialized); + this.onThreadChanged(threadId, roster); + return true; + } + + private rosterForThread(threadId: string): readonly PresenceViewer[] { + const viewers = this.viewersByThread.get(threadId); + if (viewers === undefined) { + return []; + } + return [...viewers.entries()] + .sort(([leftHandle], [rightHandle]) => + leftHandle.localeCompare(rightHandle), + ) + .map(([handle, viewer]) => { + const actor = this.firstActor(viewer); + return { + handle, + displayName: actor.displayName, + imageUrl: actor.imageUrl, + typing: viewer.typing, + }; + }); + } + + private firstActor(viewer: ViewerState): ClaimedIdentity { + for (const actor of viewer.actorsBySocket.values()) { + return actor; + } + throw new Error("Presence viewer has no subscribed sockets"); + } +} diff --git a/apps/server/src/services/threads/queued-messages.ts b/apps/server/src/services/threads/queued-messages.ts index d51d18dde3..a2a19b783a 100644 --- a/apps/server/src/services/threads/queued-messages.ts +++ b/apps/server/src/services/threads/queued-messages.ts @@ -276,6 +276,8 @@ async function sendClaimedQueuedMessageForIdleProviderThread( ensureThreadCanStartRequest(thread); const senderThreadId = args.queuedMessages[0]!.senderThreadId; + const actorHandle = + senderThreadId === null ? args.queuedMessages[0]!.actorHandle : null; let inputGroups = args.queuedMessages.map((claimedQueuedMessage) => formatQueuedMessageInputForSender({ input: toThreadQueuedMessage(claimedQueuedMessage).content, @@ -320,6 +322,7 @@ async function sendClaimedQueuedMessageForIdleProviderThread( hostId: environment.hostId, }); const preparedCommand = await prepareTurnSubmitCommandPayload(deps, { + actorHandle, environment, execution, input, @@ -339,6 +342,7 @@ async function sendClaimedQueuedMessageForIdleProviderThread( throw createQueuedMessageClaimLostError(); } const request = appendClientTurnEventInTransaction(tx, { + actorHandle, environmentId: thread.environmentId, execution, initiator, @@ -430,6 +434,10 @@ async function sendClaimedQueuedMessageForThread( thread: args.thread, }); await sendThreadMessage(deps, { + actorHandle: + args.queuedMessages[0]!.senderThreadId === null + ? args.queuedMessages[0]!.actorHandle + : null, beforeAppendInTransaction: ({ tx }) => { const consumed = deleteClaimedQueuedThreadMessageBatchInTransaction(tx, { queuedMessages: args.queuedMessages, diff --git a/apps/server/src/services/threads/thread-commands.ts b/apps/server/src/services/threads/thread-commands.ts index a4ee25350e..7d928313e3 100644 --- a/apps/server/src/services/threads/thread-commands.ts +++ b/apps/server/src/services/threads/thread-commands.ts @@ -1,6 +1,8 @@ import { environments, events, + countDistinctThreadEventActors, + getCollaborator, getAppSettings, getExperiments, threads, @@ -33,6 +35,7 @@ import { type HostDaemonAcpLaunchSpec, type HostDaemonCommand, type TurnSubmitTarget, + type TurnSpeaker, } from "@bb/host-daemon-contract"; import type { AppDeps, LoggedWorkSessionDeps } from "../../types.js"; import type { CommandResultSideEffectsDeps } from "../../internal/command-result-side-effects.js"; @@ -85,6 +88,7 @@ interface ThreadUnarchiveCommandEnvironment { } export interface ThreadStartCommandArgs { + actorHandle?: string | null; environment: ThreadStartCommandEnvironment; execution: ResolvedThreadExecutionOptions; // Non-null ⇒ clone the parent's provider session at its branch point (native @@ -101,6 +105,7 @@ export interface ThreadStartCommandArgs { } interface PreparedTurnSubmitCommandBuildArgs { + speaker?: TurnSpeaker; claudeCodeMockCliTraffic: ClaudeCodeMockCliTrafficConfig; deps: Pick; environmentId: string; @@ -115,6 +120,7 @@ interface PreparedTurnSubmitCommandBuildArgs { } interface PrepareTurnSubmitCommandPayloadArgs { + actorHandle?: string | null; environment: ThreadRuntimeCommandEnvironment; execution: ResolvedThreadExecutionOptions; permissionEscalation: PermissionEscalation; @@ -181,6 +187,28 @@ function providerSupportsThreadRename(providerId: string): boolean { return getBuiltInAgentProviderInfo(providerId).capabilities.supportsRename; } +function resolveTurnSpeaker( + deps: Pick, + args: { actorHandle?: string | null; threadId: string }, +): TurnSpeaker | undefined { + if (!args.actorHandle) { + return undefined; + } + if ( + countDistinctThreadEventActors(deps.db, { + excludedHandle: args.actorHandle, + threadId: args.threadId, + }) < 1 + ) { + return undefined; + } + const collaborator = getCollaborator(deps.db, args.actorHandle); + return { + handle: args.actorHandle, + displayName: collaborator?.displayName ?? args.actorHandle, + }; +} + function providerSupportsThreadArchiveForwarding(providerId: string): boolean { if (!isAgentProviderId(providerId)) { return false; @@ -338,6 +366,10 @@ export async function buildThreadStartCommand( model: args.execution.model, }); const acpLaunchSpec = buildAcpLaunchSpecForProviderId(deps, args.providerId); + const speaker = resolveTurnSpeaker(deps, { + actorHandle: args.actorHandle, + threadId: args.thread.id, + }); return { type: "thread.start", environmentId: args.environment.id, @@ -354,6 +386,7 @@ export async function buildThreadStartCommand( ...(args.inputGroups !== undefined ? { inputGroups: args.inputGroups } : {}), + ...(speaker !== undefined ? { speaker } : {}), options: toRuntimeExecutionOptions({ ...args, claudeCodeMockCliTraffic: resolveClaudeCodeMockCliTrafficConfig(deps), @@ -391,6 +424,7 @@ function buildPreparedTurnSubmitCommandPayload( ...(args.inputGroups !== undefined ? { inputGroups: args.inputGroups } : {}), + ...(args.speaker !== undefined ? { speaker: args.speaker } : {}), options: toRuntimeExecutionOptions({ ...args, claudeCodeMockCliTraffic: args.claudeCodeMockCliTraffic, @@ -453,6 +487,10 @@ export async function prepareTurnSubmitCommandPayload( environment: args.environment, model: args.execution.model, }); + const speaker = resolveTurnSpeaker(deps, { + actorHandle: args.actorHandle, + threadId: args.thread.id, + }); return buildPreparedTurnSubmitCommandPayload({ claudeCodeMockCliTraffic: resolveClaudeCodeMockCliTrafficConfig(deps), deps, @@ -464,6 +502,7 @@ export async function prepareTurnSubmitCommandPayload( ? { inputGroups: args.inputGroups } : {}), providerThreadId, + ...(speaker !== undefined ? { speaker } : {}), runtimeContext, target: args.target, threadId: args.thread.id, diff --git a/apps/server/src/services/threads/thread-create-helpers.ts b/apps/server/src/services/threads/thread-create-helpers.ts index 0f2bb1ed89..accec76b51 100644 --- a/apps/server/src/services/threads/thread-create-helpers.ts +++ b/apps/server/src/services/threads/thread-create-helpers.ts @@ -170,6 +170,7 @@ export function createThreadRecord( try { const thread = createThread(deps.db, deps.hub, { + createdByHandle: args.request.createdByHandle ?? null, projectId: args.request.projectId, environmentId: args.environmentId, providerId: args.request.providerId, diff --git a/apps/server/src/services/threads/thread-create-request.ts b/apps/server/src/services/threads/thread-create-request.ts index cbd768efba..219fd51df2 100644 --- a/apps/server/src/services/threads/thread-create-request.ts +++ b/apps/server/src/services/threads/thread-create-request.ts @@ -13,6 +13,7 @@ import type { } from "@bb/server-contract"; export interface ThreadCreateServiceRequestInput { + createdByHandle?: string | null; /** @deprecated Use originKind. */ childOrigin?: ThreadChildOrigin | null; /** diff --git a/apps/server/src/services/threads/thread-create.ts b/apps/server/src/services/threads/thread-create.ts index 32752f2581..0bdc947718 100644 --- a/apps/server/src/services/threads/thread-create.ts +++ b/apps/server/src/services/threads/thread-create.ts @@ -432,6 +432,10 @@ async function createProvisioningThread( "client/turn/requested", ); context = requestThreadProvision(deps, { + actorHandle: + args.request.startedOnBehalfOf === null + ? (args.request.createdByHandle ?? null) + : null, thread, environmentIntent: args.environmentIntent, execution, @@ -472,6 +476,10 @@ export async function createThreadFromRequest( visibility: NonNullable; } = { ...rawRequestInput, + createdByHandle: + rawRequestInput.origin === "plugin" + ? null + : (rawRequestInput.createdByHandle ?? null), visibility: rawRequestInput.visibility ?? "visible", }; const project = requirePublicProjectForThreadCreate( diff --git a/apps/server/src/services/threads/thread-events.ts b/apps/server/src/services/threads/thread-events.ts index b4c9d82443..f567d0d3b5 100644 --- a/apps/server/src/services/threads/thread-events.ts +++ b/apps/server/src/services/threads/thread-events.ts @@ -59,6 +59,7 @@ interface ThreadEventTransactionDeps { } export interface ClientTurnRequestedEventArgs { + actorHandle?: string | null; environmentId: string | null; execution: ResolvedThreadExecutionOptions; initiator: ThreadTurnInitiator; @@ -83,6 +84,7 @@ export interface PreparedClientTurnRequestedEventArgs extends ClientTurnRequeste } export interface ClientTurnLifecycleEventArgs { + actorHandle?: string | null; environmentId: string | null; initiator: ThreadTurnInitiator; requestMethod: "thread/start" | "turn/start"; @@ -139,6 +141,7 @@ export interface BuildCwdBranchEntriesArgs { } export interface AppendThreadInterruptedEventArgs { + actorHandle?: string | null; reason: SystemThreadInterruptedReason; threadId: string; } @@ -298,6 +301,7 @@ function appendBuiltClientTurnRequestedEvent( args: PreparedClientTurnRequestedEventArgs, ): AppendedClientTurnRequest { const sequence = append({ + actorHandle: args.actorHandle ?? null, threadId: args.threadId, environmentId: args.environmentId, type: args.type, @@ -315,6 +319,7 @@ function appendBuiltClientTurnEvent( case "client/thread/start": case "client/turn/start": return append({ + actorHandle: args.actorHandle ?? null, threadId: args.threadId, environmentId: args.environmentId, type: args.type, @@ -602,6 +607,7 @@ export function appendPreparedClientTurnRequestedEventWithNotificationInTransact args: PreparedClientTurnRequestedEventArgs, ): AppendedClientTurnRequestWithNotification { const eventArgs: AppendThreadEventArgs = { + actorHandle: args.actorHandle ?? null, threadId: args.threadId, environmentId: args.environmentId, type: args.type, @@ -811,6 +817,7 @@ export function appendThreadInterruptedEventInTransaction( args: AppendThreadInterruptedEventArgs, ): number { return appendThreadEventInTransaction(db, { + actorHandle: args.actorHandle ?? null, threadId: args.threadId, type: "system/thread/interrupted", scope: threadScope(), diff --git a/apps/server/src/services/threads/thread-lifecycle.ts b/apps/server/src/services/threads/thread-lifecycle.ts index ca7901df93..e9c4fc62a4 100644 --- a/apps/server/src/services/threads/thread-lifecycle.ts +++ b/apps/server/src/services/threads/thread-lifecycle.ts @@ -208,6 +208,7 @@ interface HasProviderTurnCompletedEventAtOrAfterArgs { } export interface RequestThreadStopArgs extends ThreadStopCommandArgs { + actorHandle?: string | null; interruptionReason: SystemThreadInterruptedReason; } @@ -421,6 +422,7 @@ interface ApplyActiveTurnInterruptionArgs { } interface MarkThreadStopRequestedWithEventArgs { + actorHandle?: string | null; reason: SystemThreadInterruptedReason; threadId: string; } @@ -491,6 +493,7 @@ function appendThreadInterruptedEventIfMissingInTransaction( return false; } appendThreadInterruptedEventInTransaction(deps.db, { + actorHandle: args.actorHandle ?? null, threadId: args.threadId, reason: args.reason, }); @@ -519,6 +522,7 @@ function markThreadStoppingWithEventInTransaction( } deps.hub.notifyThread(args.threadId, ["status-changed"]); appendThreadInterruptedEventInTransaction(deps.db, { + actorHandle: args.actorHandle ?? null, threadId: args.threadId, reason: args.reason, }); @@ -1142,6 +1146,7 @@ export function requestThreadStop( hub: notificationBuffer, }, { + actorHandle: args.actorHandle ?? null, reason: args.interruptionReason, threadId: args.threadId, }, @@ -1197,6 +1202,7 @@ function dispatchThreadStopCommand( function requestPreStartThreadStop( deps: RequestThreadStopForCurrentStateDeps, thread: RequestThreadStopForCurrentStateThread, + actorHandle?: string | null, ): void { const notificationBuffer = new NotificationBuffer(); const result: RequestPreStartThreadStopResult = deps.db.transaction( @@ -1231,6 +1237,7 @@ function requestPreStartThreadStop( if (currentThread.status !== "stopping") { markThreadStoppingWithEventInTransaction(txDeps, { + actorHandle: actorHandle ?? null, reason: "manual-stop", threadId: currentThread.id, }); @@ -1302,6 +1309,7 @@ export function requestThreadStopForCurrentState( deps: RequestThreadStopForCurrentStateDeps, thread: RequestThreadStopForCurrentStateThread, environment: RequestThreadStopForCurrentStateEnvironment | null, + actorHandle?: string | null, ): void { // An active thread (or one with a live start RPC in flight) stops via the // runtime stop RPC; a stopping thread with a live turn re-dispatches that @@ -1316,6 +1324,7 @@ export function requestThreadStopForCurrentState( return; } requestThreadStop(deps, { + actorHandle: actorHandle ?? null, environmentId: environment.id, hostId: environment.hostId, interruptionReason: "manual-stop", @@ -1329,7 +1338,7 @@ export function requestThreadStopForCurrentState( thread.status === "stopping" || hasActiveThreadProvisioningContext(thread.id) ) { - requestPreStartThreadStop(deps, thread); + requestPreStartThreadStop(deps, thread, actorHandle); } } diff --git a/apps/server/src/services/threads/thread-provisioning-context.ts b/apps/server/src/services/threads/thread-provisioning-context.ts index a4b565638f..57a78232bb 100644 --- a/apps/server/src/services/threads/thread-provisioning-context.ts +++ b/apps/server/src/services/threads/thread-provisioning-context.ts @@ -64,6 +64,7 @@ export const threadForkDescriptorSchema = z.object({ }); export const threadProvisionCommonPayloadSchema = z.object({ + actorHandle: z.string().nullable().default(null), branchSlug: z.string().nullable().default(null), clientRequestId: clientTurnRequestIdSchema, environmentIntent: threadProvisionEnvironmentIntentSchema, @@ -191,6 +192,7 @@ export type ThreadProvisionProvisionableContext = | ThreadProvisionWorkspaceReadyContext; export interface CreateMetadataPendingContextArgs { + actorHandle?: string | null; clientRequestId: ClientTurnRequestId; environmentIntent: ThreadProvisionEnvironmentIntent; execution: ResolvedThreadExecutionOptions; @@ -218,6 +220,7 @@ export interface CreateEnvironmentProvisioningContextArgs { } export interface CreateReprovisioningContextArgs { + actorHandle?: string | null; clientRequestId: ClientTurnRequestId; environmentId: string; provisionEventSequence: number; @@ -332,6 +335,7 @@ export function createMetadataPendingContext( ): ThreadProvisionMetadataPendingContext { return { request: { + actorHandle: args.actorHandle ?? null, branchSlug: null, clientRequestId: args.clientRequestId, environmentIntent: args.environmentIntent, @@ -436,6 +440,7 @@ export function createReprovisioningContext( ): ThreadProvisionEnvironmentProvisioningContext { return { request: { + actorHandle: args.actorHandle ?? null, branchSlug: null, environmentIntent: { type: "reuse", diff --git a/apps/server/src/services/threads/thread-provisioning.ts b/apps/server/src/services/threads/thread-provisioning.ts index b1438e025d..fae3c184ef 100644 --- a/apps/server/src/services/threads/thread-provisioning.ts +++ b/apps/server/src/services/threads/thread-provisioning.ts @@ -46,6 +46,7 @@ import { applyLoggedThreadLifecycleEvent } from "./lifecycle-outcome.js"; import { recordAcceptedPromptHistoryEntry } from "../prompt-history.js"; interface RequestThreadProvisionArgs { + actorHandle?: string | null; environmentIntent: ThreadProvisionEnvironmentIntent; execution: ResolvedThreadExecutionOptions; // Non-null ⇒ provision this thread by cloning the source provider session @@ -62,6 +63,7 @@ interface RequestThreadProvisionArgs { } interface RequestThreadReprovisionArgs { + actorHandle?: string | null; beforeRequestAppendInTransaction?: (args: { tx: DbTransaction }) => void; environment: Environment; provisionEventSequence: number; @@ -221,6 +223,7 @@ async function startThreadIfEnvironmentReady( // established and the thread lands idle; the user steers the first executed // turn later. Submitted fork prompts carry their input and run immediately. await requestThreadStart(deps, { + actorHandle: args.context.request.actorHandle, thread: args.thread, environment: { id: args.environment.id, @@ -255,6 +258,7 @@ export function requestThreadProvision( const senderThreadId = args.startedOnBehalfOf?.senderThreadId ?? null; const target: TurnRequestTarget = { kind: "thread-start" }; const request = appendClientTurnEvent(deps, { + actorHandle: initiator === "user" ? (args.actorHandle ?? null) : null, threadId: args.thread.id, environmentId: args.thread.environmentId, type: "client/turn/requested", @@ -274,6 +278,7 @@ export function requestThreadProvision( requestSequence: request.sequence, }); appendClientTurnEvent(deps, { + actorHandle: initiator === "user" ? (args.actorHandle ?? null) : null, threadId: args.thread.id, environmentId: args.thread.environmentId, type: "client/thread/start", @@ -307,6 +312,7 @@ export function requestThreadReprovision( tx, { threadId: args.thread.id, + actorHandle: args.actorHandle ?? null, environmentId: args.environment.id, type: "client/turn/requested", input: args.input, @@ -345,6 +351,7 @@ export function requestThreadReprovision( ); const context = createReprovisioningContext({ + actorHandle: args.actorHandle ?? null, clientRequestId: request.requestId, provisionEventSequence: args.provisionEventSequence, execution: args.execution, diff --git a/apps/server/src/services/threads/thread-send.ts b/apps/server/src/services/threads/thread-send.ts index ad1d011cd9..117bf8add7 100644 --- a/apps/server/src/services/threads/thread-send.ts +++ b/apps/server/src/services/threads/thread-send.ts @@ -68,6 +68,7 @@ type SendThreadMessagePayload = SendMessageRequest & { }; export interface SendThreadMessageArgs { + actorHandle?: string | null; beforeAppendInTransaction?: SendThreadMessageTransactionPreflight; environment: Environment; payload: SendThreadMessagePayload; @@ -114,6 +115,7 @@ interface SendThreadMessageQueueRequest { } interface AppendAndQueueSendThreadMessageArgs { + actorHandle: string | null; beforeAppendInTransaction?: SendThreadMessageTransactionPreflight; db: DbConnection; environmentId: string | null; @@ -314,6 +316,7 @@ function captureUserMessageSentTelemetry( } function appendAndQueueSendThreadMessageInTransaction({ + actorHandle, beforeAppendInTransaction, db, environmentId, @@ -335,6 +338,7 @@ function appendAndQueueSendThreadMessageInTransaction({ appendPreparedClientTurnRequestedEventWithNotificationInTransaction( tx, { + actorHandle, threadId: thread.id, environmentId, type: "client/turn/requested", @@ -392,6 +396,8 @@ export async function sendThreadMessage( senderThreadId: payload.senderThreadId, targetThread: thread, }); + const actorHandle = + senderThreadId === null ? (args.actorHandle ?? null) : null; let inputGroups = payload.inputGroups ? payload.inputGroups.map((inputGroup) => senderThreadId @@ -457,6 +463,7 @@ export async function sendThreadMessage( if ( await dispatchTurnDuringReprovision({ + actorHandle, beforeRequestAppendInTransaction: args.beforeAppendInTransaction, deps, environment, @@ -490,6 +497,7 @@ export async function sendThreadMessage( if (mode === "start") { const command = await prepareReadyThreadTurnCommand(deps, { + actorHandle, thread, // A send/steer always targets an already-started thread; forking only // happens at create time. @@ -511,6 +519,7 @@ export async function sendThreadMessage( syncGeneratedTitle: false, }); const queuedRequest = appendAndQueueSendThreadMessageInTransaction({ + actorHandle, beforeAppendInTransaction: ({ tx }) => { args.beforeAppendInTransaction?.({ tx }); ensureThreadCanStartRequest(thread); @@ -585,6 +594,7 @@ export async function sendThreadMessage( hostId: readyEnvironment.hostId, }); const preparedCommand = await prepareTurnSubmitCommandPayload(deps, { + actorHandle, thread, input, ...(inputGroups !== undefined ? { inputGroups } : {}), @@ -607,6 +617,7 @@ export async function sendThreadMessage( requestId, }); const queuedRequest = appendAndQueueSendThreadMessageInTransaction({ + actorHandle, beforeAppendInTransaction: args.beforeAppendInTransaction, db: deps.db, environmentId: thread.environmentId, diff --git a/apps/server/src/services/threads/thread-turn-dispatch.ts b/apps/server/src/services/threads/thread-turn-dispatch.ts index 917bc49df3..cd134fbfa1 100644 --- a/apps/server/src/services/threads/thread-turn-dispatch.ts +++ b/apps/server/src/services/threads/thread-turn-dispatch.ts @@ -37,6 +37,7 @@ export interface ReadyThreadEnvironment extends Environment { } export interface DispatchTurnDuringReprovisionArgs { + actorHandle?: string | null; beforeRequestAppendInTransaction?: (args: { tx: DbTransaction }) => void; deps: LoggedPendingInteractionWorkSessionDeps; environment: Environment; @@ -171,6 +172,7 @@ export async function dispatchTurnDuringReprovision( { beforeProvisionCommandStart: () => { requestThreadReprovision(args.deps, { + actorHandle: args.actorHandle ?? null, beforeRequestAppendInTransaction: args.beforeRequestAppendInTransaction, thread: args.thread, diff --git a/apps/server/src/ws/client-protocol.ts b/apps/server/src/ws/client-protocol.ts index dd7cdb6c2b..56e9683aad 100644 --- a/apps/server/src/ws/client-protocol.ts +++ b/apps/server/src/ws/client-protocol.ts @@ -52,9 +52,7 @@ export function onClientSocketMessage( deps.watchInterests.unsubscribe(socket, parsed.target); break; case "typing": - // Presence typing signal; folded into presence state by the hub once - // multiplayer presence lands. Accepted (not an error) so newer clients - // never get their socket closed by an older server mid-rollout. + deps.hub.setTyping(socket, parsed.threadId, parsed.typing); break; default: { const _exhaustive: never = parsed; @@ -70,7 +68,7 @@ export function onClientSocketClose( }, socket: ClientSocket, ): void { - releaseSocketActor(socket); deps.watchInterests.releaseSocket(socket); deps.hub.unregisterClient(socket); + releaseSocketActor(socket); } diff --git a/apps/server/src/ws/hub.ts b/apps/server/src/ws/hub.ts index 50c2c3fc5c..aba8515be0 100644 --- a/apps/server/src/ws/hub.ts +++ b/apps/server/src/ws/hub.ts @@ -8,6 +8,7 @@ import { type SystemChangeKind, type ThreadChangeKind, type ThreadChangeMetadata, + type PresenceViewer, } from "@bb/domain"; import type { DbNotifier } from "@bb/db"; import type { @@ -19,8 +20,10 @@ import type { } from "@bb/host-daemon-contract"; import { pluginSignalSchema, + presenceSummaryMessageSchema, serverMessageSchema, terminalServerMessageSchema, + threadPresenceMessageSchema, threadOpenSignalSchema, threadPaneActionSignalSchema, type ThreadPaneAction, @@ -28,6 +31,10 @@ import { type ThreadOpenSplit, type TerminalServerMessage, } from "@bb/server-contract"; +import { + PresenceService, + type PresenceSnapshot, +} from "../services/presence.js"; interface HubSocket { close(code?: number, reason?: string): void; @@ -103,6 +110,10 @@ export interface RecordHostOnlineRpcResponseArgs { sessionId: string; } +export interface NotificationHubOptions { + presenceTypingTtlMs?: number; +} + export type HostOnlineRpcResponseDisposition = | { handled: true } | { handled: false; reason: "stale" } @@ -168,6 +179,18 @@ export class NotificationHub implements DbNotifier { string, Set >(); + private readonly presence: PresenceService; + + constructor(options: NotificationHubOptions = {}) { + this.presence = new PresenceService({ + onThreadChanged: (threadId, viewers) => { + this.broadcastPresence(threadId, viewers); + }, + ...(options.presenceTypingTtlMs === undefined + ? {} + : { typingTtlMs: options.presenceTypingTtlMs }), + }); + } registerClient(socket: HubSocket): void { if (!this.clientKeysBySocket.has(socket)) { @@ -191,6 +214,10 @@ export class NotificationHub implements DbNotifier { if (sockets.size === 0) { this.clientSocketsByKey.delete(key); } + const threadId = this.threadIdFromDetailKey(key); + if (threadId !== null) { + this.presence.unsubscribe(threadId, socket); + } } this.clientKeysBySocket.delete(socket); @@ -279,16 +306,24 @@ export class NotificationHub implements DbNotifier { subscribe(socket: HubSocket, target: RealtimeSubscriptionTarget): void { this.registerClient(socket); const key = subscriptionKey(target); - this.clientKeysBySocket.get(socket)?.add(key); + const keys = this.clientKeysBySocket.get(socket); + const alreadySubscribed = keys?.has(key) ?? false; + keys?.add(key); const sockets = this.clientSocketsByKey.get(key) ?? new Set(); sockets.add(socket); this.clientSocketsByKey.set(key, sockets); + if (target.kind === "thread-detail" && !alreadySubscribed) { + const result = this.presence.subscribe(target.threadId, socket); + if (result === "unchanged") { + this.sendThreadPresenceToSocket(socket, target.threadId); + } + } } unsubscribe(socket: HubSocket, target: RealtimeSubscriptionTarget): void { const key = subscriptionKey(target); - this.clientKeysBySocket.get(socket)?.delete(key); + const wasSubscribed = this.clientKeysBySocket.get(socket)?.delete(key); const sockets = this.clientSocketsByKey.get(key); if (!sockets) { @@ -298,6 +333,17 @@ export class NotificationHub implements DbNotifier { if (sockets.size === 0) { this.clientSocketsByKey.delete(key); } + if (target.kind === "thread-detail" && wasSubscribed) { + this.presence.unsubscribe(target.threadId, socket); + } + } + + setTyping(socket: HubSocket, threadId: string, typing: boolean): void { + this.presence.setTyping(socket, threadId, typing); + } + + getPresenceSnapshot(): PresenceSnapshot { + return this.presence.snapshot(); } recordDaemonSessionPlatform(sessionId: string, platform: HostPlatform): void { @@ -771,6 +817,66 @@ export class NotificationHub implements DbNotifier { this.daemonRegistrationWaiters.delete(hostId); } + /** + * Presence summaries are partial patches: consumers merge the supplied + * thread entries into their cache, and an empty handle array removes that + * thread's entry. + */ + private broadcastPresence( + threadId: string, + viewers: readonly PresenceViewer[], + ): void { + const detailResult = threadPresenceMessageSchema.safeParse({ + type: "thread-presence", + threadId, + viewers, + }); + const summaryResult = presenceSummaryMessageSchema.safeParse({ + type: "presence-summary", + threads: { [threadId]: viewers.map((viewer) => viewer.handle) }, + }); + if (!detailResult.success || !summaryResult.success) { + console.error( + "Skipping invalid realtime presence broadcast", + detailResult.success ? summaryResult.error : detailResult.error, + ); + return; + } + + this.notifyClientsByKeySet( + this.clientSocketsByKey.get( + subscriptionKey({ kind: "thread-detail", threadId }), + ) ?? [], + JSON.stringify(detailResult.data), + ); + this.notifyClientsByKeySet( + this.clientSocketsByKey.get(subscriptionKey({ kind: "thread-list" })) ?? + [], + JSON.stringify(summaryResult.data), + ); + } + + private sendThreadPresenceToSocket( + socket: HubSocket, + threadId: string, + ): void { + const result = threadPresenceMessageSchema.safeParse({ + type: "thread-presence", + threadId, + viewers: this.presence.snapshot().threads[threadId] ?? [], + }); + if (!result.success) { + console.error("Skipping invalid realtime presence sync", result.error); + return; + } + socket.send(JSON.stringify(result.data)); + } + + private threadIdFromDetailKey(key: string): string | null { + const prefix = "thread-detail:"; + return key.startsWith(prefix) ? key.slice(prefix.length) : null; + } + private notifyClients(message: ChangedMessage): void { const sockets = new Set(); for (const key of subscriptionKeysForMessage(message)) { diff --git a/apps/server/test/app/presence.test.ts b/apps/server/test/app/presence.test.ts new file mode 100644 index 0000000000..d4b521b32d --- /dev/null +++ b/apps/server/test/app/presence.test.ts @@ -0,0 +1,244 @@ +import { + presenceSummaryMessageSchema, + threadPresenceMessageSchema, +} from "@bb/server-contract"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { + onClientSocketClose, + onClientSocketMessage, + onClientSocketOpen, +} from "../../src/ws/client-protocol.js"; +import { NotificationHub } from "../../src/ws/hub.js"; +import { + registerSocketActor, + releaseSocketActor, +} from "../../src/ws/socket-actors.js"; +import { createMockHubSocket } from "../helpers/mock-hub-socket.js"; + +const sawyer = { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + clientId: "browser-1", +} as const; + +function messages(socket: ReturnType) { + return socket.messages.map((message) => JSON.parse(message) as unknown); +} + +function protocolDeps(hub: NotificationHub) { + return { + hub, + watchInterests: { + releaseSocket: vi.fn(), + subscribe: vi.fn(), + unsubscribe: vi.fn(), + }, + }; +} + +afterEach(() => { + vi.useRealTimers(); +}); + +describe("thread presence", () => { + it("broadcasts strict detail and partial-summary payloads on subscribe and unsubscribe", () => { + const hub = new NotificationHub(); + const detailSocket = createMockHubSocket(); + const listSocket = createMockHubSocket(); + registerSocketActor(detailSocket, sawyer); + hub.subscribe(listSocket, { kind: "thread-list" }); + + hub.subscribe(detailSocket, { + kind: "thread-detail", + threadId: "thread-1", + }); + + const detail = threadPresenceMessageSchema.parse(messages(detailSocket)[0]); + const summary = presenceSummaryMessageSchema.parse(messages(listSocket)[0]); + expect(detail).toEqual({ + type: "thread-presence", + threadId: "thread-1", + viewers: [ + { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + typing: false, + }, + ], + }); + expect(summary).toEqual({ + type: "presence-summary", + threads: { "thread-1": ["sawyer"] }, + }); + expect(hub.getPresenceSnapshot()).toEqual({ + threads: { "thread-1": detail.viewers }, + }); + + hub.unsubscribe(detailSocket, { + kind: "thread-detail", + threadId: "thread-1", + }); + + expect(presenceSummaryMessageSchema.parse(messages(listSocket)[1])).toEqual( + { + type: "presence-summary", + threads: { "thread-1": [] }, + }, + ); + expect(hub.getPresenceSnapshot()).toEqual({ threads: {} }); + releaseSocketActor(detailSocket); + }); + + it("skips presence broadcasts that fail the strict outgoing schemas", () => { + const consoleError = vi + .spyOn(console, "error") + .mockImplementation(() => {}); + try { + const hub = new NotificationHub(); + const socket = createMockHubSocket(); + registerSocketActor(socket, { + ...sawyer, + displayName: "", + }); + + hub.subscribe(socket, { + kind: "thread-detail", + threadId: "thread-1", + }); + + expect(socket.messages).toHaveLength(0); + expect(consoleError).toHaveBeenCalledWith( + "Skipping invalid realtime presence broadcast", + expect.anything(), + ); + hub.unregisterClient(socket); + releaseSocketActor(socket); + } finally { + consoleError.mockRestore(); + } + }); + + it("dedupes a handle across sockets and removes it only after the last socket closes", () => { + const hub = new NotificationHub(); + const firstSocket = createMockHubSocket(); + const secondSocket = createMockHubSocket(); + const listSocket = createMockHubSocket(); + registerSocketActor(firstSocket, sawyer); + registerSocketActor(secondSocket, { ...sawyer, clientId: "browser-2" }); + hub.subscribe(listSocket, { kind: "thread-list" }); + hub.subscribe(firstSocket, { + kind: "thread-detail", + threadId: "thread-1", + }); + firstSocket.messages.length = 0; + listSocket.messages.length = 0; + + hub.subscribe(secondSocket, { + kind: "thread-detail", + threadId: "thread-1", + }); + + expect(messages(secondSocket)).toEqual([ + { + type: "thread-presence", + threadId: "thread-1", + viewers: [ + { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + typing: false, + }, + ], + }, + ]); + expect(firstSocket.messages).toHaveLength(0); + expect(listSocket.messages).toHaveLength(0); + + hub.unregisterClient(firstSocket); + expect(listSocket.messages).toHaveLength(0); + expect(hub.getPresenceSnapshot().threads["thread-1"]).toHaveLength(1); + + hub.unregisterClient(secondSocket); + expect(messages(listSocket)).toEqual([ + { + type: "presence-summary", + threads: { "thread-1": [] }, + }, + ]); + expect(hub.getPresenceSnapshot()).toEqual({ threads: {} }); + releaseSocketActor(firstSocket); + releaseSocketActor(secondSocket); + }); + + it("expires typing after the TTL and suppresses unchanged rebroadcasts", async () => { + vi.useFakeTimers(); + const hub = new NotificationHub({ presenceTypingTtlMs: 50 }); + const detailSocket = createMockHubSocket(); + const listSocket = createMockHubSocket(); + registerSocketActor(detailSocket, sawyer); + hub.subscribe(listSocket, { kind: "thread-list" }); + hub.subscribe(detailSocket, { + kind: "thread-detail", + threadId: "thread-1", + }); + detailSocket.messages.length = 0; + listSocket.messages.length = 0; + + hub.subscribe(detailSocket, { + kind: "thread-detail", + threadId: "thread-1", + }); + expect(detailSocket.messages).toHaveLength(0); + + hub.setTyping(detailSocket, "thread-1", true); + expect( + threadPresenceMessageSchema.parse(messages(detailSocket)[0]).viewers[0] + ?.typing, + ).toBe(true); + expect(listSocket.messages).toHaveLength(1); + + hub.setTyping(detailSocket, "thread-1", true); + expect(detailSocket.messages).toHaveLength(1); + expect(listSocket.messages).toHaveLength(1); + + await vi.advanceTimersByTimeAsync(50); + expect( + threadPresenceMessageSchema.parse(messages(detailSocket)[1]).viewers[0] + ?.typing, + ).toBe(false); + expect(listSocket.messages).toHaveLength(2); + releaseSocketActor(detailSocket); + }); + + it("folds typing protocol messages into presence and removes presence before releasing the actor", () => { + const hub = new NotificationHub(); + const deps = protocolDeps(hub); + const socket = createMockHubSocket(); + registerSocketActor(socket, sawyer); + onClientSocketOpen(hub, socket); + onClientSocketMessage( + deps, + socket, + JSON.stringify({ + type: "subscribe", + target: { kind: "thread-detail", threadId: "thread-1" }, + }), + ); + socket.messages.length = 0; + + onClientSocketMessage( + deps, + socket, + JSON.stringify({ type: "typing", threadId: "thread-1", typing: true }), + ); + + expect( + threadPresenceMessageSchema.parse(messages(socket)[0]).viewers[0]?.typing, + ).toBe(true); + onClientSocketClose(deps, socket); + expect(hub.getPresenceSnapshot()).toEqual({ threads: {} }); + }); +}); diff --git a/apps/server/test/public/public-presence.test.ts b/apps/server/test/public/public-presence.test.ts new file mode 100644 index 0000000000..ddde79d604 --- /dev/null +++ b/apps/server/test/public/public-presence.test.ts @@ -0,0 +1,41 @@ +import { presenceSnapshotResponseSchema } from "@bb/server-contract"; +import { describe, expect, it } from "vitest"; +import { registerSocketActor } from "../../src/ws/socket-actors.js"; +import { createMockHubSocket } from "../helpers/mock-hub-socket.js"; +import { readJson } from "../helpers/json.js"; +import { withTestHarness } from "../helpers/test-app.js"; + +describe("GET /api/v1/presence", () => { + it("returns the current hub-derived viewer snapshot", async () => { + await withTestHarness(async (harness) => { + const socket = createMockHubSocket(); + registerSocketActor(socket, { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + clientId: "browser-1", + }); + harness.hub.subscribe(socket, { + kind: "thread-detail", + threadId: "thread-1", + }); + + const response = await harness.app.request("/api/v1/presence"); + expect(response.status).toBe(200); + expect( + presenceSnapshotResponseSchema.parse(await readJson(response)), + ).toEqual({ + threads: { + "thread-1": [ + { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + typing: false, + }, + ], + }, + }); + }); + }); +}); diff --git a/apps/server/test/public/public-thread-data.test.ts b/apps/server/test/public/public-thread-data.test.ts index 861ff3f553..ce6534549b 100644 --- a/apps/server/test/public/public-thread-data.test.ts +++ b/apps/server/test/public/public-thread-data.test.ts @@ -19,6 +19,8 @@ import { upsertProjectExecutionDefaults, } from "@bb/db"; import { + CLAIMED_IDENTITY_HEADER, + encodeClaimedIdentityHeader, encodeClientTurnRequestIdNumber, threadQueuedMessageSchema, threadScope, @@ -92,6 +94,85 @@ const clientTurnRequestedDataSchema = z.object({ type TimelineTurnRow = Extract; describe("public thread data routes", () => { + it("attributes direct human sends to the resolved request actor", async () => { + await withTestHarness(async (harness) => { + const { thread } = seedThreadFixture(harness); + const response = await harness.app.request( + `/api/v1/threads/${thread.id}/send`, + { + method: "POST", + headers: { + "content-type": "application/json", + [CLAIMED_IDENTITY_HEADER]: encodeClaimedIdentityHeader({ + clientId: "browser-alice", + displayName: "Alice", + handle: "alice", + imageUrl: null, + }), + }, + body: JSON.stringify({ + input: [{ type: "text", text: "Human-authored message" }], + mode: "start", + model: "gpt-5", + permissionMode: "full", + reasoningLevel: "medium", + serviceTier: "default", + }), + }, + ); + + expect(response.status, await response.clone().text()).toBe(200); + expect( + harness.db + .select({ actorHandle: events.actorHandle }) + .from(events) + .where( + and( + eq(events.threadId, thread.id), + eq(events.type, "client/turn/requested"), + ), + ) + .get(), + ).toEqual({ actorHandle: "alice" }); + }); + }); + + it("attributes manual stops to the resolved request actor", async () => { + await withTestHarness(async (harness) => { + const { thread } = seedThreadFixture(harness, { + thread: { status: "active" }, + }); + const response = await harness.app.request( + `/api/v1/threads/${thread.id}/stop`, + { + method: "POST", + headers: { + [CLAIMED_IDENTITY_HEADER]: encodeClaimedIdentityHeader({ + clientId: "browser-alice", + displayName: "Alice", + handle: "alice", + imageUrl: null, + }), + }, + }, + ); + + expect(response.status).toBe(200); + expect( + harness.db + .select({ actorHandle: events.actorHandle }) + .from(events) + .where( + and( + eq(events.threadId, thread.id), + eq(events.type, "system/thread/interrupted"), + ), + ) + .get(), + ).toEqual({ actorHandle: "alice" }); + }); + }); + it("manages sections through the canonical public route lifecycle", async () => { await withTestHarness(async (harness) => { const { host } = seedHostSession(harness.deps); @@ -2818,6 +2899,12 @@ describe("public thread data routes", () => { method: "POST", headers: { "content-type": "application/json", + [CLAIMED_IDENTITY_HEADER]: encodeClaimedIdentityHeader({ + clientId: "browser-alice", + displayName: "Alice", + handle: "alice", + imageUrl: null, + }), }, body: JSON.stringify({ input: [{ type: "text", text: "Queued message ready to send" }], @@ -2844,7 +2931,7 @@ describe("public thread data routes", () => { }); expect("inputGroups" in queued.command).toBe(false); const requestedEvent = harness.db - .select({ data: events.data }) + .select({ actorHandle: events.actorHandle, data: events.data }) .from(events) .where( and( @@ -2852,8 +2939,11 @@ describe("public thread data routes", () => { eq(events.type, "client/turn/requested"), ), ) - .get(); + .orderBy(events.sequence) + .all() + .at(-1); expect(requestedEvent).toBeTruthy(); + expect(requestedEvent?.actorHandle).toBe("alice"); expect( Object.hasOwn(JSON.parse(requestedEvent!.data), "inputGroups"), ).toBe(false); diff --git a/apps/server/test/public/public-thread-interactions.test.ts b/apps/server/test/public/public-thread-interactions.test.ts index dc10258bab..aab83752da 100644 --- a/apps/server/test/public/public-thread-interactions.test.ts +++ b/apps/server/test/public/public-thread-interactions.test.ts @@ -1,5 +1,11 @@ -import { createQueuedThreadMessage, listQueuedThreadMessages } from "@bb/db"; import { + createQueuedThreadMessage, + getPendingInteraction, + listQueuedThreadMessages, +} from "@bb/db"; +import { + CLAIMED_IDENTITY_HEADER, + encodeClaimedIdentityHeader, turnScope, USER_QUESTION_MAX_FREE_TEXT_LENGTH, USER_QUESTION_MAX_SELECTED, @@ -338,6 +344,12 @@ describe("public thread interaction routes", () => { method: "POST", headers: { "content-type": "application/json", + [CLAIMED_IDENTITY_HEADER]: encodeClaimedIdentityHeader({ + clientId: "browser-alice", + displayName: "Alice", + handle: "alice", + imageUrl: null, + }), }, body: JSON.stringify(createAllowOnceResolution()), }, @@ -348,6 +360,10 @@ describe("public thread interaction routes", () => { status: "resolving", resolution: createAllowOnceResolution(), }); + expect( + getPendingInteraction(harness.db, registered.interaction.id) + ?.resolvedByHandle, + ).toBe("alice"); const duplicateResolveResponse = await harness.app.request( `/api/v1/threads/${thread.id}/interactions/${registered.interaction.id}/resolve`, @@ -947,9 +963,9 @@ describe("public thread interaction routes", () => { message: "Thread is awaiting user interaction. Resolve the pending interaction before sending another prompt.", }); - expect(listQueuedThreadMessages(harness.db, activeThread.id)).toHaveLength( - 0, - ); + expect( + listQueuedThreadMessages(harness.db, activeThread.id), + ).toHaveLength(0); }); }); diff --git a/apps/server/test/public/public-threads.project-default.test.ts b/apps/server/test/public/public-threads.project-default.test.ts index ab680eeaea..5b4a793327 100644 --- a/apps/server/test/public/public-threads.project-default.test.ts +++ b/apps/server/test/public/public-threads.project-default.test.ts @@ -1,5 +1,11 @@ import { getThread } from "@bb/db"; -import { PERSONAL_PROJECT_ID, threadSchema } from "@bb/domain"; +import { + CLAIMED_IDENTITY_HEADER, + PERSONAL_PROJECT_ID, + encodeClaimedIdentityHeader, + threadSchema, + type ClaimedIdentity, +} from "@bb/domain"; import { describe, expect, it } from "vitest"; import { resolveProjectDefaultThreadEnvironment } from "../../src/services/threads/thread-default-policy.js"; import { @@ -17,6 +23,7 @@ import { import { withTestHarness, type TestAppHarness } from "../helpers/test-app.js"; interface CreateThreadBodyOverrides { + claimedIdentity?: ClaimedIdentity; environment: unknown; origin?: string; originPluginId?: string; @@ -29,7 +36,16 @@ async function postCreateThread( ): Promise { return harness.app.request("/api/v1/threads", { method: "POST", - headers: { "content-type": "application/json" }, + headers: { + "content-type": "application/json", + ...(overrides.claimedIdentity !== undefined + ? { + [CLAIMED_IDENTITY_HEADER]: encodeClaimedIdentityHeader( + overrides.claimedIdentity, + ), + } + : {}), + }, body: JSON.stringify({ origin: overrides.origin ?? "sdk", ...(overrides.originPluginId !== undefined @@ -106,13 +122,10 @@ describe("project-default thread environment", () => { hostId: host.id, path: sourcePath, }); - const { provision, threadId } = await createAndCaptureProvision( - harness, - { - projectId: project.id, - environment: { type: "project-default" }, - }, - ); + const { provision, threadId } = await createAndCaptureProvision(harness, { + projectId: project.id, + environment: { type: "project-default" }, + }); expect(provision).toEqual(explicit); // Non-plugin origins surface a null plugin attribution. expect(getThread(harness.db, threadId)?.originPluginId).toBeNull(); @@ -153,6 +166,33 @@ describe("project-default thread environment", () => { }); describe("plugin thread attribution", () => { + it("records the creator for human origins", async () => { + await withTestHarness(async (harness) => { + const { host } = seedHostSession(harness.deps); + const { project } = seedProjectWithSource(harness.deps, { + hostId: host.id, + }); + const response = await postCreateThread(harness, project.id, { + claimedIdentity: { + clientId: "browser-alice", + displayName: "Alice", + handle: "alice", + imageUrl: null, + }, + environment: { + type: "host", + hostId: host.id, + workspace: { type: "unmanaged", path: null }, + }, + origin: "app", + }); + + expect(response.status).toBe(201); + const created = threadSchema.parse(await readJson(response)); + expect(getThread(harness.db, created.id)?.createdByHandle).toBe("alice"); + }); + }); + it("persists and surfaces originPluginId for plugin-origin threads", async () => { await withTestHarness(async (harness) => { const { host } = seedHostSession(harness.deps); @@ -168,6 +208,12 @@ describe("plugin thread attribution", () => { }); const response = await postCreateThread(harness, project.id, { + claimedIdentity: { + clientId: "browser-alice", + displayName: "Alice", + handle: "alice", + imageUrl: null, + }, origin: "plugin", originPluginId: "linear", environment: { @@ -180,6 +226,7 @@ describe("plugin thread attribution", () => { const created = threadSchema.parse(await readJson(response)); expect(created.originPluginId).toBe("linear"); expect(getThread(harness.db, created.id)?.originPluginId).toBe("linear"); + expect(getThread(harness.db, created.id)?.createdByHandle).toBeNull(); const getResponse = await harness.app.request( `/api/v1/threads/${created.id}`, diff --git a/apps/server/test/services/threads/thread-speaker.test.ts b/apps/server/test/services/threads/thread-speaker.test.ts new file mode 100644 index 0000000000..df1bd3c710 --- /dev/null +++ b/apps/server/test/services/threads/thread-speaker.test.ts @@ -0,0 +1,84 @@ +import { appendStoredThreadEvent, upsertCollaborator } from "@bb/db"; +import { threadScope } from "@bb/domain"; +import { describe, expect, it } from "vitest"; +import { prepareTurnSubmitCommandPayload } from "../../../src/services/threads/thread-commands.js"; +import { textInput } from "../../helpers/prompt-input.js"; +import { + seedEnvironment, + seedHostSession, + seedProjectWithSource, + seedThread, +} from "../../helpers/seed.js"; +import { withTestHarness } from "../../helpers/test-app.js"; + +const execution = { + model: "gpt-5", + permissionMode: "full", + reasoningLevel: "medium", + serviceTier: "default", + source: "client/turn/requested", +} as const; + +describe("thread turn speakers", () => { + it("adds a speaker only once a different human has acted in the thread", async () => { + await withTestHarness(async (harness) => { + const { host } = seedHostSession(harness.deps); + const { project } = seedProjectWithSource(harness.deps, { + hostId: host.id, + }); + const environment = seedEnvironment(harness.deps, { + hostId: host.id, + path: "/tmp/thread-speaker", + projectId: project.id, + }); + const thread = seedThread(harness.deps, { + environmentId: environment.id, + projectId: project.id, + }); + upsertCollaborator( + harness.db, + { displayName: "Alice", handle: "alice", imageUrl: null }, + 1, + ); + upsertCollaborator( + harness.db, + { displayName: "Bob", handle: "bob", imageUrl: null }, + 1, + ); + appendStoredThreadEvent(harness.db, harness.hub, { + actorHandle: "alice", + data: { reason: "manual-stop" }, + scope: threadScope(), + threadId: thread.id, + type: "system/thread/interrupted", + }); + + const singleHuman = await prepareTurnSubmitCommandPayload(harness.deps, { + actorHandle: "alice", + environment, + execution, + input: textInput("same speaker"), + permissionEscalation: "deny", + providerThreadId: "provider-thread-speaker", + target: { mode: "start" }, + thread, + }); + expect(singleHuman).not.toHaveProperty("speaker"); + + const multiplayer = await prepareTurnSubmitCommandPayload(harness.deps, { + actorHandle: "bob", + environment, + execution, + input: textInput("new speaker"), + permissionEscalation: "deny", + providerThreadId: "provider-thread-speaker", + target: { mode: "start" }, + thread, + }); + expect(multiplayer.speaker).toEqual({ + displayName: "Bob", + handle: "bob", + }); + }); + }); +}); diff --git a/packages/db/src/data/events.ts b/packages/db/src/data/events.ts index 751f89178f..cbd82f0fc2 100644 --- a/packages/db/src/data/events.ts +++ b/packages/db/src/data/events.ts @@ -1,5 +1,6 @@ import { and, + countDistinct, desc, eq, gt, @@ -11,6 +12,7 @@ import { max, notExists, notInArray, + ne, or, sql, } from "drizzle-orm"; @@ -65,6 +67,7 @@ const isNotNestedTurnUsageEvent = sql`NOT EXISTS ( const isEnvironmentDirectoryUpdateEventData = sql`json_extract(${events.data}, '$.operation') = 'environment_directory_update'`; export interface InsertEventInput { + actorHandle?: string | null; threadId: string; environmentId?: string | null; scope: ThreadEventScope; @@ -132,6 +135,7 @@ export type AppendStoredThreadEventArgs< TType extends ThreadEventType = ThreadEventType, > = { [TEventType in TType]: { + actorHandle?: string | null; data: StoredThreadEventDataForType; environmentId?: string | null; providerThreadId?: string | null; @@ -194,8 +198,8 @@ export function insertEvents( const createdAt = input.createdAt ?? Date.now(); const turnId = getThreadEventScopeTurnId(input.scope) ?? null; const result = db.run( - sql`INSERT OR IGNORE INTO events (id, thread_id, environment_id, scope_kind, turn_id, provider_thread_id, sequence, type, item_id, item_kind, data, created_at) - VALUES (${id}, ${input.threadId}, ${input.environmentId ?? null}, ${input.scope.kind}, ${turnId}, ${input.providerThreadId ?? null}, ${input.sequence}, ${input.type}, ${input.itemId}, ${input.itemKind}, ${input.data}, ${createdAt})`, + sql`INSERT OR IGNORE INTO events (id, thread_id, environment_id, scope_kind, turn_id, provider_thread_id, sequence, type, item_id, item_kind, actor_handle, data, created_at) + VALUES (${id}, ${input.threadId}, ${input.environmentId ?? null}, ${input.scope.kind}, ${turnId}, ${input.providerThreadId ?? null}, ${input.sequence}, ${input.type}, ${input.itemId}, ${input.itemKind}, ${input.actorHandle ?? null}, ${input.data}, ${createdAt})`, ); if (result.changes > 0) { insertedCount++; @@ -585,7 +589,7 @@ export function appendStoredThreadEventsInTransaction( db.run( sql`INSERT INTO events - (id, thread_id, environment_id, scope_kind, turn_id, provider_thread_id, sequence, type, item_id, item_kind, data, created_at) + (id, thread_id, environment_id, scope_kind, turn_id, provider_thread_id, sequence, type, item_id, item_kind, actor_handle, data, created_at) VALUES ( ${createEventId()}, ${args.threadId}, @@ -597,6 +601,7 @@ export function appendStoredThreadEventsInTransaction( ${args.type}, ${itemFields.itemId}, ${itemFields.itemKind}, + ${args.actorHandle ?? null}, ${JSON.stringify(args.data)}, ${now} )`, @@ -616,6 +621,29 @@ export function appendStoredThreadEventsInTransaction( return sequences; } +export function countDistinctThreadEventActors( + db: DbQueryConnection, + args: { + excludedHandle?: string; + threadId: string; + }, +): number { + const row = db + .select({ actorCount: countDistinct(events.actorHandle) }) + .from(events) + .where( + and( + eq(events.threadId, args.threadId), + isNotNull(events.actorHandle), + args.excludedHandle === undefined + ? undefined + : ne(events.actorHandle, args.excludedHandle), + ), + ) + .get(); + return row?.actorCount ?? 0; +} + export function appendStoredThreadEvent( db: DbConnection, notifier: DbNotifier, diff --git a/packages/db/src/data/index.ts b/packages/db/src/data/index.ts index 2d12bdda82..b1390c0272 100644 --- a/packages/db/src/data/index.ts +++ b/packages/db/src/data/index.ts @@ -303,6 +303,7 @@ export { getLatestThreadOutputEventRow, getLatestThreadSystemErrorEventRow, getLatestThreadSequence, + countDistinctThreadEventActors, insertEvents, listActiveBackgroundTaskCountsByThreadIds, listContextWindowUsageRows, @@ -451,6 +452,7 @@ export { setPendingInteractionInterrupted, setPendingInteractionResolving, setPendingInteractionResolved, + setPendingInteractionResolvedByHandle, } from "./pending-interactions.js"; export type { CreatePendingInteractionInput, diff --git a/packages/db/src/data/pending-interactions.ts b/packages/db/src/data/pending-interactions.ts index 72dfd849ab..01d3597998 100644 --- a/packages/db/src/data/pending-interactions.ts +++ b/packages/db/src/data/pending-interactions.ts @@ -1,4 +1,4 @@ -import { and, desc, eq, inArray } from "drizzle-orm"; +import { and, desc, eq, inArray, isNull } from "drizzle-orm"; import type { SQL } from "drizzle-orm"; import type { PendingInteractionStatus } from "@bb/domain"; import type { DbConnection, DbTransaction } from "../connection.js"; @@ -285,6 +285,28 @@ export function setPendingInteractionResolved( }); } +export function setPendingInteractionResolvedByHandle( + db: PendingInteractionWriteConnection, + args: { + id: string; + resolvedByHandle: string; + }, +): PendingInteractionRow | null { + return ( + db + .update(pendingInteractions) + .set({ resolvedByHandle: args.resolvedByHandle }) + .where( + and( + eq(pendingInteractions.id, args.id), + isNull(pendingInteractions.resolvedByHandle), + ), + ) + .returning() + .get() ?? null + ); +} + export function setPendingInteractionResolving( db: PendingInteractionWriteConnection, args: SetPendingInteractionResolvingArgs, diff --git a/packages/db/src/data/queued-thread-messages.ts b/packages/db/src/data/queued-thread-messages.ts index 13598a940c..00fa7cebbc 100644 --- a/packages/db/src/data/queued-thread-messages.ts +++ b/packages/db/src/data/queued-thread-messages.ts @@ -26,6 +26,7 @@ import { } from "./order-keys.js"; export interface CreateQueuedThreadMessageInput { + actorHandle?: string | null; threadId: string; content: PromptInput[]; senderThreadId?: string | null; @@ -216,6 +217,7 @@ function queuedMessageGroupingEnvelopeMatches( ): boolean { return ( firstQueuedMessage !== null && + queuedMessage.actorHandle === firstQueuedMessage.actorHandle && queuedMessage.senderThreadId === firstQueuedMessage.senderThreadId && queuedMessage.model === firstQueuedMessage.model && queuedMessage.reasoningLevel === firstQueuedMessage.reasoningLevel && @@ -491,6 +493,7 @@ export function createQueuedThreadMessage( threadId: input.threadId, content: JSON.stringify(input.content), senderThreadId: input.senderThreadId ?? null, + actorHandle: input.actorHandle ?? null, model: input.model, reasoningLevel: input.reasoningLevel, permissionMode: input.permissionMode, diff --git a/packages/db/src/data/threads.ts b/packages/db/src/data/threads.ts index 46555f5dd8..7a072bbe55 100644 --- a/packages/db/src/data/threads.ts +++ b/packages/db/src/data/threads.ts @@ -243,6 +243,7 @@ export function upsertThreadTitleSearchSegments( } export interface CreateThreadInput { + createdByHandle?: string | null; projectId: string; environmentId?: string | null; providerId: string; @@ -290,6 +291,7 @@ export function createThread( originKind, childOrigin: null, originPluginId: input.originPluginId ?? null, + createdByHandle: input.createdByHandle ?? null, visibility, lastReadAt: now, latestAttentionAt: now, diff --git a/packages/db/test/data/events.test.ts b/packages/db/test/data/events.test.ts index a898c94c39..aae9212e26 100644 --- a/packages/db/test/data/events.test.ts +++ b/packages/db/test/data/events.test.ts @@ -17,6 +17,7 @@ import { appendStoredThreadEvent, appendStoredThreadEventInTransaction, appendStoredThreadEventsInTransaction, + countDistinctThreadEventActors, findStoredEventRow, getActiveStoredTurnId, getHighWaterMarks, @@ -200,6 +201,51 @@ describe("events", () => { expect(all).toHaveLength(2); }); + it("stores event actors and counts distinct human speakers", () => { + const { db, thread } = setup(); + + insertEvents(db, noopNotifier, [ + { + actorHandle: "alice", + threadId: thread.id, + sequence: 1, + type: "system/error", + ...threadEventFields, + data: JSON.stringify({ message: "first" }), + }, + { + actorHandle: "bob", + threadId: thread.id, + sequence: 2, + type: "system/error", + ...threadEventFields, + data: JSON.stringify({ message: "second" }), + }, + { + threadId: thread.id, + sequence: 3, + type: "system/error", + ...threadEventFields, + data: JSON.stringify({ message: "system" }), + }, + ]); + + expect(listEvents(db, { threadId: thread.id })).toMatchObject([ + { actorHandle: "alice" }, + { actorHandle: "bob" }, + { actorHandle: null }, + ]); + expect( + countDistinctThreadEventActors(db, { threadId: thread.id }), + ).toBe(2); + expect( + countDistinctThreadEventActors(db, { + excludedHandle: "alice", + threadId: thread.id, + }), + ).toBe(1); + }); + it("stores derived item columns when provided", () => { const { db, thread } = setup(); diff --git a/packages/db/test/data/pending-interactions.test.ts b/packages/db/test/data/pending-interactions.test.ts index a5372826f8..205a2d7fea 100644 --- a/packages/db/test/data/pending-interactions.test.ts +++ b/packages/db/test/data/pending-interactions.test.ts @@ -13,6 +13,7 @@ import { interruptPendingInteractionsForThreads, listPendingInteractionsByThread, setPendingInteractionResolved, + setPendingInteractionResolvedByHandle, } from "../../src/data/pending-interactions.js"; import { createThread } from "../../src/data/threads.js"; @@ -169,6 +170,18 @@ describe("pending interactions", () => { id: older.id, status: "resolved", }); + expect( + setPendingInteractionResolvedByHandle(db, { + id: older.id, + resolvedByHandle: "alice", + }), + ).toMatchObject({ resolvedByHandle: "alice" }); + expect( + setPendingInteractionResolvedByHandle(db, { + id: older.id, + resolvedByHandle: "bob", + }), + ).toBeNull(); }); it("interrupts pending interactions for matching provider threads only", () => { diff --git a/packages/db/test/data/queued-thread-messages.test.ts b/packages/db/test/data/queued-thread-messages.test.ts index b25bc91ab5..c1903035fb 100644 --- a/packages/db/test/data/queued-thread-messages.test.ts +++ b/packages/db/test/data/queued-thread-messages.test.ts @@ -54,6 +54,7 @@ describe("queued thread messages", () => { it("creates a queued message", () => { const { db, thread } = setup(); const queuedMessage = createQueuedThreadMessage(db, noopNotifier, { + actorHandle: "alice", threadId: thread.id, content: defaultInput, model: "gpt-5", @@ -65,6 +66,7 @@ describe("queued thread messages", () => { expect(queuedMessage.id).toMatch(/^qmsg_/); expect(queuedMessage.threadId).toBe(thread.id); expect(queuedMessage.content).toBe(JSON.stringify(defaultInput)); + expect(queuedMessage.actorHandle).toBe("alice"); expect(queuedMessage.model).toBe("gpt-5"); expect(queuedMessage.serviceTier).toBe("default"); expect(queuedMessage.groupWithNext).toBe(false); diff --git a/packages/db/test/data/threads.test.ts b/packages/db/test/data/threads.test.ts index 502a775f37..142143b3d1 100644 --- a/packages/db/test/data/threads.test.ts +++ b/packages/db/test/data/threads.test.ts @@ -67,6 +67,18 @@ function mustCreateThreadSection( } describe("threads", () => { + it("records the human creator handle", () => { + const { db, project } = setup(); + const thread = createThread(db, noopNotifier, { + createdByHandle: "alice", + projectId: project.id, + providerId: "codex", + }); + + expect(thread.createdByHandle).toBe("alice"); + expect(getThread(db, thread.id)?.createdByHandle).toBe("alice"); + }); + it("summarizes favicon attention for active sidebar threads", () => { vi.useFakeTimers(); try { diff --git a/packages/host-daemon-contract/src/commands.ts b/packages/host-daemon-contract/src/commands.ts index 5d2858b90a..8f099e7756 100644 --- a/packages/host-daemon-contract/src/commands.ts +++ b/packages/host-daemon-contract/src/commands.ts @@ -35,7 +35,7 @@ import { providerCliStatusResponseSchema, } from "./local.js"; -export const HOST_DAEMON_PROTOCOL_VERSION = 58 as const; +export const HOST_DAEMON_PROTOCOL_VERSION = 59 as const; export { BRANCH_LIST_LIMIT_MAX, @@ -256,6 +256,14 @@ interface GroupedPromptInputCommand { inputGroups?: HostDaemonPromptInput[][]; } +export const turnSpeakerSchema = z + .object({ + handle: z.string().min(1), + displayName: z.string().min(1), + }) + .strict(); +export type TurnSpeaker = z.infer; + function flattenPromptInputGroups( inputGroups: readonly HostDaemonPromptInput[][], ): HostDaemonPromptInput[] { @@ -296,6 +304,7 @@ export const threadStartCommandSchema = hostDaemonThreadTargetSchema // at least one input, enforced by the refinement below. input: z.array(promptInputSchema), inputGroups: z.array(z.array(promptInputSchema).min(1)).min(1).optional(), + speaker: turnSpeakerSchema.optional(), threadStoragePath: z.string().min(1).optional(), /** Present means fork the new thread from this source provider session * instead of starting fresh; absent means a normal start. */ @@ -338,6 +347,7 @@ const turnSubmitCommandSchema = hostDaemonThreadTargetSchema requestId: clientTurnRequestIdSchema, input: z.array(promptInputSchema).min(1), inputGroups: z.array(z.array(promptInputSchema).min(1)).min(1).optional(), + speaker: turnSpeakerSchema.optional(), options: runtimeThreadExecutionOptionsSchema, acpLaunchSpec: hostDaemonAcpLaunchSpecSchema.optional(), resumeContext: turnResumeContextSchema, diff --git a/packages/host-daemon-contract/test/contract.test.ts b/packages/host-daemon-contract/test/contract.test.ts index d357674f06..9906d3ce3a 100644 --- a/packages/host-daemon-contract/test/contract.test.ts +++ b/packages/host-daemon-contract/test/contract.test.ts @@ -655,6 +655,8 @@ const INTENTIONAL_OPTIONAL_HOST_DAEMON_FIELDS: Record = { "ACP permission CLI config omits insertAfterArgs when permission args should be inserted before all configured agent args.", "hostDaemonCommandSchema.checkout": "environment.provision only includes checkout instructions for unmanaged workspaces that requested a branch mutation.", + "hostDaemonCommandSchema.speaker": + "turn commands omit speaker attribution until a thread has more than one distinct human actor.", "hostDaemonCommandSchema.targetPath": "project.clone omits targetPath when the daemon should derive its default checkout location for the project.", "hostDaemonOnlineRpcCommandSchema.expectedSha256": @@ -1666,7 +1668,7 @@ describe("host-daemon command schemas", () => { }); it("parses section mentions in thread.start", () => { - expect(HOST_DAEMON_PROTOCOL_VERSION).toBeGreaterThanOrEqual(58); + expect(HOST_DAEMON_PROTOCOL_VERSION).toBeGreaterThanOrEqual(59); expect( hostDaemonCommandSchema.parse({ diff --git a/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts b/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts index 37ace07d88..8e4d1b38d2 100644 --- a/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts +++ b/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts @@ -3089,8 +3089,8 @@ declare const environmentDiffFileResponseSchema: z$1.ZodObject<{ path: z$1.ZodString; content: z$1.ZodString; contentEncoding: z$1.ZodEnum<{ - base64: "base64"; utf8: "utf8"; + base64: "base64"; }>; mimeType: z$1.ZodOptional; sizeBytes: z$1.ZodNumber; @@ -3297,10 +3297,10 @@ declare const environmentPullRequestResponseSchema: z$1.ZodDiscriminatedUnion<[z mergeability: z$1.ZodObject<{ state: z$1.ZodEnum<{ unknown: "unknown"; + blocked: "blocked"; draft: "draft"; mergeable: "mergeable"; conflicts: "conflicts"; - blocked: "blocked"; }>; mergeStateStatus: z$1.ZodNullable; attention: z$1.ZodEnum<{ none: "none"; + blocked: "blocked"; 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"; @@ -3912,6 +3912,10 @@ declare const hostDaemonCommandRegistry: { sizeBytes: z$1.ZodOptional; mimeType: z$1.ZodOptional; }, z$1.core.$strip>], "type">>>>; + speaker: z$1.ZodOptional>; threadStoragePath: z$1.ZodOptional; fork: z$1.ZodOptional; mimeType: z$1.ZodOptional; }, z$1.core.$strip>], "type">>>>; + speaker: z$1.ZodOptional>; options: z$1.ZodIntersection; devMode: z$1.ZodOptional>; installed: z$1.ZodObject<{ @@ -5825,11 +5833,11 @@ declare const installedPluginSchema: z$1.ZodObject<{ sourceDisplay: z$1.ZodString; updateState: z$1.ZodObject<{ outcome: z$1.ZodOptional>; availableVersion: z$1.ZodOptional; blockedVersion: z$1.ZodOptional; @@ -5918,11 +5926,11 @@ declare const pluginListResponseSchema: z$1.ZodObject<{ sourceDisplay: z$1.ZodString; updateState: z$1.ZodObject<{ outcome: z$1.ZodOptional>; availableVersion: z$1.ZodOptional; blockedVersion: z$1.ZodOptional; @@ -6012,11 +6020,11 @@ declare const pluginReloadResponseSchema: z$1.ZodObject<{ sourceDisplay: z$1.ZodString; updateState: z$1.ZodObject<{ outcome: z$1.ZodOptional>; availableVersion: z$1.ZodOptional; blockedVersion: z$1.ZodOptional; diff --git a/packages/server-contract/src/api-types.ts b/packages/server-contract/src/api-types.ts index 392a5ce8d6..ddb1d65d0f 100644 --- a/packages/server-contract/src/api-types.ts +++ b/packages/server-contract/src/api-types.ts @@ -4,6 +4,7 @@ export * from "./api/environments.js"; export * from "./api/files.js"; export * from "./api/hosts.js"; export * from "./api/plugins.js"; +export * from "./api/presence.js"; export * from "./api/system.js"; export * from "./api/terminals.js"; export * from "./api/threads.js"; diff --git a/packages/server-contract/src/api/presence.ts b/packages/server-contract/src/api/presence.ts new file mode 100644 index 0000000000..7e0ac656fe --- /dev/null +++ b/packages/server-contract/src/api/presence.ts @@ -0,0 +1,19 @@ +import { presenceViewerSchema } from "@bb/domain"; +import { z } from "zod"; + +/** + * Complete current ephemeral viewer rosters, keyed by thread id. + * + * Unlike this HTTP snapshot, realtime `presence-summary` messages are partial + * patches: merge each supplied thread entry into the local summary, and remove + * an entry when its supplied handle array is empty. + */ +export const presenceSnapshotResponseSchema = z + .object({ + threads: z.record(z.string(), z.array(presenceViewerSchema).readonly()), + }) + .strict(); + +export type PresenceSnapshotResponse = z.infer< + typeof presenceSnapshotResponseSchema +>; diff --git a/packages/server-contract/src/index.ts b/packages/server-contract/src/index.ts index 3025faede3..97bffd26e9 100644 --- a/packages/server-contract/src/index.ts +++ b/packages/server-contract/src/index.ts @@ -26,6 +26,9 @@ export { HOST_CHANGE_KINDS, hostChangedMessageSchema, hostChangeKindSchema, + presenceSummaryMessageLenientSchema, + presenceSummaryMessageSchema, + presenceViewerSchema, PROJECT_CHANGE_KINDS, projectChangedMessageSchema, projectChangeKindSchema, @@ -38,6 +41,8 @@ export { threadChangeKindSchema, threadChangeMetadataSchema, THREAD_CHANGE_KINDS, + threadPresenceMessageLenientSchema, + threadPresenceMessageSchema, } from "@bb/domain"; export type { @@ -47,6 +52,8 @@ export type { EnvironmentChangedMessage, HostChangeKind, HostChangedMessage, + PresenceSummaryMessage, + PresenceViewer, ProjectChangeKind, ProjectChangedMessage, RealtimeSubscriptionTarget, @@ -56,6 +63,7 @@ export type { ThreadChangeMetadata, ThreadChangeKind, ThreadChangedMessage, + ThreadPresenceMessage, UnsubscribeMessage, JsonValue, } from "@bb/domain"; diff --git a/packages/server-contract/src/public-api.ts b/packages/server-contract/src/public-api.ts index 5c7e9ea52f..d339d1ae8a 100644 --- a/packages/server-contract/src/public-api.ts +++ b/packages/server-contract/src/public-api.ts @@ -115,6 +115,7 @@ import type { ProjectWithThreadsResponse, PromptHistoryQuery, PromptHistoryResponse, + PresenceSnapshotResponse, ReorderPinnedThreadRequest, ReorderProjectRequest, ReorderQueuedMessageRequest, @@ -1175,6 +1176,15 @@ export const publicApiRoutes = { }), }, + presence: { + snapshot: defineRoute({ + path: "/presence", + method: "get", + request: noRequest(), + response: jsonResponse(), + }), + }, + system: { attention: defineRoute({ path: "/system/attention", diff --git a/packages/server-contract/test/presence.test.ts b/packages/server-contract/test/presence.test.ts new file mode 100644 index 0000000000..02ab0ee894 --- /dev/null +++ b/packages/server-contract/test/presence.test.ts @@ -0,0 +1,69 @@ +import { describe, expect, it } from "vitest"; +import { + presenceSummaryMessageSchema, + presenceSnapshotResponseSchema, + threadPresenceMessageLenientSchema, + threadPresenceMessageSchema, +} from "../src/index.js"; + +describe("presence contracts", () => { + it("validates strict snapshots and realtime messages", () => { + const viewer = { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + typing: false, + }; + expect( + presenceSnapshotResponseSchema.parse({ + threads: { "thread-1": [viewer] }, + }), + ).toEqual({ threads: { "thread-1": [viewer] } }); + expect( + threadPresenceMessageSchema.parse({ + type: "thread-presence", + threadId: "thread-1", + viewers: [viewer], + }), + ).toMatchObject({ type: "thread-presence", threadId: "thread-1" }); + expect( + presenceSummaryMessageSchema.parse({ + type: "presence-summary", + threads: { "thread-1": ["sawyer"] }, + }), + ).toEqual({ + type: "presence-summary", + threads: { "thread-1": ["sawyer"] }, + }); + }); + + it("rejects unknown strict fields while lenient inbound parsing strips them", () => { + const message = { + type: "thread-presence", + threadId: "thread-1", + viewers: [ + { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + typing: false, + futureViewerField: true, + }, + ], + futureMessageField: true, + }; + expect(threadPresenceMessageSchema.safeParse(message).success).toBe(false); + expect(threadPresenceMessageLenientSchema.parse(message)).toEqual({ + type: "thread-presence", + threadId: "thread-1", + viewers: [ + { + handle: "sawyer", + displayName: "Sawyer", + imageUrl: null, + typing: false, + }, + ], + }); + }); +}); From 5cfbcb1905a630253f97171c784491b2844b7d6c Mon Sep 17 00:00:00 2001 From: Sawyer Hood Date: Sat, 18 Jul 2026 09:51:21 -0700 Subject: [PATCH 4/8] Multiplayer wave 2.5: expose actorHandle on the event read path and /ws identity fallback The attribution column landed write-only in wave 2; this threads it through every read surface so the UI can render authorship: StoredEventRow -> EventMeta -> EventProjectionUserMessage -> TimelineUserConversationRow, plus the raw events endpoint's ThreadEventRow wrapper. Client-side schemas default actorHandle to null when parsing responses from pre-multiplayer servers. Also: /ws accepts the claimed identity via an `identity` query parameter carrying the same encoded payload, because browsers cannot set custom headers on WebSocket upgrades. Includes regenerated plugin-sdk bundled types and templates, and test-fixture updates for the now-required meta field. Co-Authored-By: Claude Fable 5 --- .../secondary-panel/SideChatTabContent.tsx | 1 + .../thread/timeline/StreamingRows.stories.tsx | 3 ++ .../timeline/rows/UnreadDivider.stories.tsx | 1 + .../toc/ThreadTableOfContents.stories.tsx | 1 + .../thread/toc/ThreadTableOfContents.test.tsx | 1 + .../thread-runtime-cache-owner.ts | 1 + .../src/lib/side-chat-create-request.test.ts | 1 + .../src/test/fixtures/thread-timeline-rows.ts | 1 + .../useThreadTimelinePages.test.ts | 1 + .../command-output/thread-log.test.ts | 1 + .../command-output/thread-wait.test.ts | 1 + .../helpers/command-output-fixtures.ts | 1 + apps/server/src/server.ts | 10 ++++- .../src/services/threads/thread-data.ts | 1 + .../threads/thread-runtime-display.ts | 1 + apps/server/src/services/threads/timeline.ts | 1 + .../threads/timeline-pagination.test.ts | 1 + packages/db/src/data/events.ts | 1 + packages/domain/src/stored-thread-event.ts | 6 +++ .../bundled-types/bb-plugin-sdk.d.ts | 38 ++++++++++--------- .../server-contract/src/thread-timeline.ts | 3 ++ .../src/generated/plugin-sdk-dts.generated.ts | 2 +- .../thread-view/src/build-thread-timeline.ts | 2 + packages/thread-view/src/event-decode.ts | 4 ++ .../src/event-projection-message.ts | 3 ++ .../thread-view/src/parse-error-message.ts | 1 + .../thread-view/src/user-message-parsing.ts | 1 + .../accepted-client-request-context.test.ts | 1 + .../test/background-task-timeline.test.ts | 1 + .../test/build-thread-timeline.test.ts | 15 ++++++++ .../test/completed-turn-grouping.test.ts | 1 + .../test/goal-snapshot-extraction.test.ts | 2 + .../test/model-fallback-extraction.test.ts | 7 +++- .../test/timeline-progression.test.ts | 2 + .../thread-view/test/timeline-test-harness.ts | 2 + .../test/todo-snapshot-extraction.test.ts | 5 ++- .../test/tool-activity-projection.test.ts | 1 + .../test/user-message-parsing.test.ts | 1 + .../fake/smoke/timeline-response.test.ts | 1 + 39 files changed, 106 insertions(+), 22 deletions(-) diff --git a/apps/app/src/components/secondary-panel/SideChatTabContent.tsx b/apps/app/src/components/secondary-panel/SideChatTabContent.tsx index b8aa7d7443..88bdd8f4b1 100644 --- a/apps/app/src/components/secondary-panel/SideChatTabContent.tsx +++ b/apps/app/src/components/secondary-panel/SideChatTabContent.tsx @@ -247,6 +247,7 @@ function buildOptimisticSideChatUserRow({ } return { + actorHandle: null, id: `${tabId}:optimistic-first-user-message`, threadId, turnId: `${tabId}:optimistic-first-user-turn`, diff --git a/apps/app/src/components/thread/timeline/StreamingRows.stories.tsx b/apps/app/src/components/thread/timeline/StreamingRows.stories.tsx index 98bde8088c..3cb4ab41ab 100644 --- a/apps/app/src/components/thread/timeline/StreamingRows.stories.tsx +++ b/apps/app/src/components/thread/timeline/StreamingRows.stories.tsx @@ -174,6 +174,7 @@ const OPTIMISTIC_USER_PROMPT_TEXT = function buildOptimisticUserRow(id: string): TimelineRow { return { + actorHandle: null, id, threadId: THREAD_ID, turnId: `${id}-turn`, @@ -303,6 +304,7 @@ function conversationRowFromStep( }; if (step.role === "user") { return { + actorHandle: null, ...base, role: "user", initiator: "user", @@ -439,6 +441,7 @@ function AssistantContentStreaming({ // invalidate the memo on in-place mutations. const turnId = "streaming-rows-content-turn"; const userRow: TimelineRow = { + actorHandle: null, id: "streaming-rows-content-user", threadId: THREAD_ID, turnId, diff --git a/apps/app/src/components/thread/timeline/rows/UnreadDivider.stories.tsx b/apps/app/src/components/thread/timeline/rows/UnreadDivider.stories.tsx index 12288bdf57..6f8665e15a 100644 --- a/apps/app/src/components/thread/timeline/rows/UnreadDivider.stories.tsx +++ b/apps/app/src/components/thread/timeline/rows/UnreadDivider.stories.tsx @@ -34,6 +34,7 @@ function userRow(args: { createdAt: number; }): TimelineRow { return { + actorHandle: null, id: `${THREAD_ID}:user:${args.seq}`, threadId: THREAD_ID, turnId: `${TURN_PREFIX}${args.seq}`, diff --git a/apps/app/src/components/thread/toc/ThreadTableOfContents.stories.tsx b/apps/app/src/components/thread/toc/ThreadTableOfContents.stories.tsx index 11b00a9091..39b5f5a48d 100644 --- a/apps/app/src/components/thread/toc/ThreadTableOfContents.stories.tsx +++ b/apps/app/src/components/thread/toc/ThreadTableOfContents.stories.tsx @@ -39,6 +39,7 @@ function conversationRow({ }; if (role === "user") { return { + actorHandle: null, ...base, role: "user", initiator: "user", diff --git a/apps/app/src/components/thread/toc/ThreadTableOfContents.test.tsx b/apps/app/src/components/thread/toc/ThreadTableOfContents.test.tsx index a489676351..93b2b1a634 100644 --- a/apps/app/src/components/thread/toc/ThreadTableOfContents.test.tsx +++ b/apps/app/src/components/thread/toc/ThreadTableOfContents.test.tsx @@ -50,6 +50,7 @@ class ResizeObserverMock implements ResizeObserver { function userConversationRow(index = 1): TimelineRow { return { + actorHandle: null, id: `row_user_${index}`, threadId: "thr_toc_test", turnId: `turn_${index}`, diff --git a/apps/app/src/hooks/cache-owners/thread-runtime-cache-owner.ts b/apps/app/src/hooks/cache-owners/thread-runtime-cache-owner.ts index 86cec56ce7..7b8a26f93d 100644 --- a/apps/app/src/hooks/cache-owners/thread-runtime-cache-owner.ts +++ b/apps/app/src/hooks/cache-owners/thread-runtime-cache-owner.ts @@ -593,6 +593,7 @@ function buildOptimisticUserMessageRow({ } : null; return { + actorHandle: null, id, kind: "conversation", role: "user", diff --git a/apps/app/src/lib/side-chat-create-request.test.ts b/apps/app/src/lib/side-chat-create-request.test.ts index 85677e79aa..003c83ec08 100644 --- a/apps/app/src/lib/side-chat-create-request.test.ts +++ b/apps/app/src/lib/side-chat-create-request.test.ts @@ -28,6 +28,7 @@ function conversationRow( }; return role === "user" ? { + actorHandle: null, ...base, role: "user", initiator: "user", diff --git a/apps/app/src/test/fixtures/thread-timeline-rows.ts b/apps/app/src/test/fixtures/thread-timeline-rows.ts index d88494455b..531ec7f546 100644 --- a/apps/app/src/test/fixtures/thread-timeline-rows.ts +++ b/apps/app/src/test/fixtures/thread-timeline-rows.ts @@ -432,6 +432,7 @@ export function conversationRow({ if (role === "user") { const resolvedInitiator: ThreadTurnInitiator = initiator ?? "user"; return { + actorHandle: null, ...rowBase, kind: "conversation", role, diff --git a/apps/app/src/views/thread-detail/useThreadTimelinePages.test.ts b/apps/app/src/views/thread-detail/useThreadTimelinePages.test.ts index a4a6dbd310..0d97089998 100644 --- a/apps/app/src/views/thread-detail/useThreadTimelinePages.test.ts +++ b/apps/app/src/views/thread-detail/useThreadTimelinePages.test.ts @@ -29,6 +29,7 @@ function timelineCursor(args: TimelineTestRowArgs): TimelinePaginationCursor { function userRow(args: TimelineTestRowArgs): TimelineUserConversationRow { return { + actorHandle: null, id: args.id, threadId: "thread-1", turnId: "turn-1", diff --git a/apps/cli/src/__tests__/command-output/thread-log.test.ts b/apps/cli/src/__tests__/command-output/thread-log.test.ts index 00494a462a..1353293920 100644 --- a/apps/cli/src/__tests__/command-output/thread-log.test.ts +++ b/apps/cli/src/__tests__/command-output/thread-log.test.ts @@ -62,6 +62,7 @@ describe("bb thread log command output", () => { const getTimeline = vi.fn(async () => fixtures.makeTimelineResponse([ { + actorHandle: null, ...fixtures.makeTimelineBase({ id: "user-1", sourceSeqStart: 1, diff --git a/apps/cli/src/__tests__/command-output/thread-wait.test.ts b/apps/cli/src/__tests__/command-output/thread-wait.test.ts index 551a536475..906e1f921f 100644 --- a/apps/cli/src/__tests__/command-output/thread-wait.test.ts +++ b/apps/cli/src/__tests__/command-output/thread-wait.test.ts @@ -160,6 +160,7 @@ describe("bb thread wait command output", () => { threadId: "thread-t0", seq: 3, createdAt: Date.now(), + actorHandle: null, event: { type: "turn/completed", threadId: "thread-t0", diff --git a/apps/cli/src/__tests__/helpers/command-output-fixtures.ts b/apps/cli/src/__tests__/helpers/command-output-fixtures.ts index d1ae1ed642..667a3b8908 100644 --- a/apps/cli/src/__tests__/helpers/command-output-fixtures.ts +++ b/apps/cli/src/__tests__/helpers/command-output-fixtures.ts @@ -85,6 +85,7 @@ export function makeTimelineResponse( export function makePendingSteerTimelineRow(): TimelineUserConversationRow { return { + actorHandle: null, ...makeTimelineBase({ id: "pending-steer-1", sourceSeqStart: 12, diff --git a/apps/server/src/server.ts b/apps/server/src/server.ts index 2ae60cb36a..dff56768a2 100644 --- a/apps/server/src/server.ts +++ b/apps/server/src/server.ts @@ -72,6 +72,7 @@ import { type PluginCatalogService, } from "./services/plugin-catalog/plugin-catalog-service.js"; import { callHostRetryableOnlineRpc } from "./services/hosts/online-rpc.js"; +import { CLAIMED_IDENTITY_HEADER } from "@bb/domain"; import { createActorService, createLocalOperatorIdentity, @@ -484,7 +485,14 @@ export function createApp( app.get( "/ws", upgradeWebSocket((context) => { - const actor = actorService.resolveRequest(context.req); + // Browsers cannot set custom headers on a WebSocket upgrade, so /ws also + // accepts the same encoded identity via the `identity` query parameter. + const identityParam = context.req.query("identity"); + const actor = actorService.resolveRequest({ + header: (name) => + context.req.header(name) ?? + (name === CLAIMED_IDENTITY_HEADER ? identityParam : undefined), + }); return { onOpen: (_event, socket) => { registerSocketActor(socket, actor); diff --git a/apps/server/src/services/threads/thread-data.ts b/apps/server/src/services/threads/thread-data.ts index 6251bf0b59..8b9f03b98c 100644 --- a/apps/server/src/services/threads/thread-data.ts +++ b/apps/server/src/services/threads/thread-data.ts @@ -105,6 +105,7 @@ export function parseStoredEventRow(row: StoredEventRow): ThreadEventRow { threadId: row.threadId, seq: row.sequence, createdAt: row.createdAt, + actorHandle: row.actorHandle, event: parseStoredEvent(row), }); } diff --git a/apps/server/src/services/threads/thread-runtime-display.ts b/apps/server/src/services/threads/thread-runtime-display.ts index 4b04a3494d..30766faafa 100644 --- a/apps/server/src/services/threads/thread-runtime-display.ts +++ b/apps/server/src/services/threads/thread-runtime-display.ts @@ -259,6 +259,7 @@ function toThreadEventWithMeta(row: StoredEventRow): ThreadEventWithMeta { id: row.id, seq: row.sequence, createdAt: row.createdAt, + actorHandle: row.actorHandle, }, }; } diff --git a/apps/server/src/services/threads/timeline.ts b/apps/server/src/services/threads/timeline.ts index 9dcbad0be1..7e45294d7d 100644 --- a/apps/server/src/services/threads/timeline.ts +++ b/apps/server/src/services/threads/timeline.ts @@ -230,6 +230,7 @@ export function toThreadEventWithMeta( id: row.id, seq: row.sequence, createdAt: row.createdAt, + actorHandle: row.actorHandle, }, }; } diff --git a/apps/server/test/services/threads/timeline-pagination.test.ts b/apps/server/test/services/threads/timeline-pagination.test.ts index 49ba27a213..7638cacb1a 100644 --- a/apps/server/test/services/threads/timeline-pagination.test.ts +++ b/apps/server/test/services/threads/timeline-pagination.test.ts @@ -11,6 +11,7 @@ function userRow(args: { text: string; }): TimelineUserConversationRow { return { + actorHandle: null, id: args.id, kind: "conversation", role: "user", diff --git a/packages/db/src/data/events.ts b/packages/db/src/data/events.ts index cbd82f0fc2..eebf7b1a05 100644 --- a/packages/db/src/data/events.ts +++ b/packages/db/src/data/events.ts @@ -715,6 +715,7 @@ export interface ListEventsOptions { } const storedEventRowFields = { + actorHandle: events.actorHandle, createdAt: events.createdAt, data: events.data, id: events.id, diff --git a/packages/domain/src/stored-thread-event.ts b/packages/domain/src/stored-thread-event.ts index bfc116c1e8..3011402980 100644 --- a/packages/domain/src/stored-thread-event.ts +++ b/packages/domain/src/stored-thread-event.ts @@ -31,6 +31,9 @@ interface ThreadEventRowBase { threadId: string; seq: number; createdAt: number; + // Claimed handle of the human who initiated the event; null = not + // human-initiated or pre-multiplayer history. + actorHandle: string | null; } interface ThreadEventRowInput extends ThreadEventRowBase { @@ -76,6 +79,8 @@ const threadEventRowInputSchema = z.object({ type: threadEventTypeSchema, data: z.record(z.string(), z.unknown()), createdAt: z.number(), + // Defaulted for rows serialized by pre-multiplayer servers. + actorHandle: z.string().nullable().default(null), }); const storedTurnRequestTypeSet = new Set([ @@ -179,6 +184,7 @@ function parseThreadEventRowInput(row: ThreadEventRowInput): ThreadEventRow { threadId: row.threadId, seq: row.seq, createdAt: row.createdAt, + actorHandle: row.actorHandle, event: parseStoredThreadEvent({ type: row.type, data: row.data, diff --git a/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts b/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts index 8e4d1b38d2..24ae2e5c15 100644 --- a/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts +++ b/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts @@ -2382,6 +2382,7 @@ interface ThreadEventRowBase { threadId: string; seq: number; createdAt: number; + actorHandle: string | null; } type ThreadEventRowFromEvent = ThreadEventRowBase & { type: TEvent["type"]; @@ -2693,9 +2694,9 @@ declare const projectBranchesResponseSchema: z$1.ZodObject<{ selectedBranch: z$1.ZodNullable; }, z$1.core.$strip>>; defaultWorktreeBaseBranch: z$1.ZodNullable; @@ -3016,9 +3017,9 @@ declare const environmentDiffBranchesResponseSchema: z$1.ZodObject<{ selectedBranch: z$1.ZodNullable; }, z$1.core.$strip>>; }, z$1.core.$strip>; @@ -3103,8 +3104,8 @@ declare const environmentArchiveThreadsResponseSchema: z$1.ZodObject<{ type EnvironmentArchiveThreadsResponse = z$1.infer; declare const pullRequestMergeMethodSchema: z$1.ZodEnum<{ merge: "merge"; - rebase: "rebase"; squash: "squash"; + rebase: "rebase"; }>; type PullRequestMergeMethod = z$1.infer; declare const commitActionResponseSchema: z$1.ZodObject<{ @@ -3135,8 +3136,8 @@ declare const pullRequestMergeActionResponseSchema: z$1.ZodObject<{ action: z$1.ZodLiteral<"pull_request_merge">; method: z$1.ZodEnum<{ merge: "merge"; - rebase: "rebase"; squash: "squash"; + rebase: "rebase"; }>; message: z$1.ZodString; }, z$1.core.$strip>; @@ -3745,8 +3746,8 @@ declare const hostDaemonCommandRegistry: { }, z$1.core.$strict>], "kind">>; disallowedTools: z$1.ZodOptional>; instructionMode: z$1.ZodEnum<{ - append: "append"; replace: "replace"; + append: "append"; }>; type: z$1.ZodLiteral<"thread.start">; requestId: z$1.ZodString; @@ -4242,8 +4243,8 @@ declare const hostDaemonCommandRegistry: { }>; }, z$1.core.$strip>; instructionMode: z$1.ZodEnum<{ - append: "append"; replace: "replace"; + append: "append"; }>; projectId: z$1.ZodString; providerId: z$1.ZodString; @@ -5154,9 +5155,9 @@ declare const hostDaemonCommandRegistry: { executablePath: z$1.ZodNullable; installed: z$1.ZodBoolean; installSource: z$1.ZodEnum<{ - external: "external"; notInstalled: "notInstalled"; npmGlobal: "npmGlobal"; + external: "external"; }>; currentVersion: z$1.ZodNullable; latestVersion: z$1.ZodNullable; @@ -5329,13 +5330,13 @@ declare const hostDaemonCommandRegistry: { 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"; - unknown: "unknown"; }>; workspacePath: z$1.ZodString; message: z$1.ZodString; @@ -5379,13 +5380,13 @@ declare const hostDaemonCommandRegistry: { 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"; - unknown: "unknown"; }>; workspacePath: z$1.ZodString; message: z$1.ZodString; @@ -5441,13 +5442,13 @@ declare const hostDaemonCommandRegistry: { 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"; - unknown: "unknown"; }>; workspacePath: z$1.ZodString; message: z$1.ZodString; @@ -5489,13 +5490,13 @@ declare const hostDaemonCommandRegistry: { 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"; - unknown: "unknown"; }>; workspacePath: z$1.ZodString; message: z$1.ZodString; @@ -5613,9 +5614,9 @@ declare const providerCliStatusResponseSchema: z$1.ZodRecord; installed: z$1.ZodBoolean; installSource: z$1.ZodEnum<{ - external: "external"; notInstalled: "notInstalled"; npmGlobal: "npmGlobal"; + external: "external"; }>; currentVersion: z$1.ZodNullable; latestVersion: z$1.ZodNullable; @@ -5856,8 +5857,8 @@ declare const installedPluginSchema: z$1.ZodObject<{ status: z$1.ZodEnum<{ error: "error"; running: "running"; - missing: "missing"; incompatible: "incompatible"; + missing: "missing"; disabled: "disabled"; degraded: "degraded"; "needs-configuration": "needs-configuration"; @@ -5949,8 +5950,8 @@ declare const pluginListResponseSchema: z$1.ZodObject<{ status: z$1.ZodEnum<{ error: "error"; running: "running"; - missing: "missing"; incompatible: "incompatible"; + missing: "missing"; disabled: "disabled"; degraded: "degraded"; "needs-configuration": "needs-configuration"; @@ -6043,8 +6044,8 @@ declare const pluginReloadResponseSchema: z$1.ZodObject<{ status: z$1.ZodEnum<{ error: "error"; running: "running"; - missing: "missing"; incompatible: "incompatible"; + missing: "missing"; disabled: "disabled"; degraded: "degraded"; "needs-configuration": "needs-configuration"; @@ -6623,9 +6624,9 @@ declare const terminalSessionSchema: z$1.ZodObject<{ cols: z$1.ZodNumber; rows: z$1.ZodNumber; status: z$1.ZodEnum<{ + running: "running"; starting: "starting"; disconnected: "disconnected"; - running: "running"; exited: "exited"; }>; exitCode: z$1.ZodNullable; @@ -6654,9 +6655,9 @@ declare const terminalListResponseSchema: z$1.ZodObject<{ cols: z$1.ZodNumber; rows: z$1.ZodNumber; status: z$1.ZodEnum<{ + running: "running"; starting: "starting"; disconnected: "disconnected"; - running: "running"; exited: "exited"; }>; exitCode: z$1.ZodNullable; @@ -6769,6 +6770,7 @@ declare const timelineConversationRowSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodO system: "system"; }>; senderThreadId: z$1.ZodNullable; + actorHandle: z$1.ZodDefault>; systemMessageKind: z$1.ZodEnum<{ "ownership-assigned": "ownership-assigned"; "ownership-removed": "ownership-removed"; @@ -9030,8 +9032,8 @@ declare const threadTimelineResponseSchema: z$1.ZodObject<{ updatedAt: z$1.ZodNumber; objective: z$1.ZodString; status: z$1.ZodEnum<{ - active: "active"; paused: "paused"; + active: "active"; budgetLimited: "budgetLimited"; complete: "complete"; }>; diff --git a/packages/server-contract/src/thread-timeline.ts b/packages/server-contract/src/thread-timeline.ts index c844d84e0c..db7541372b 100644 --- a/packages/server-contract/src/thread-timeline.ts +++ b/packages/server-contract/src/thread-timeline.ts @@ -110,6 +110,9 @@ export const timelineUserConversationRowSchema = role: z.literal("user"), initiator: threadTurnInitiatorSchema, senderThreadId: z.string().nullable(), + // Claimed handle of the human author; null = not human-initiated or + // pre-multiplayer history. Defaulted for pre-multiplayer servers. + actorHandle: z.string().nullable().default(null), // Family-B taxonomy fields, required on the read model. `systemMessageKind` // is non-nullable (legacy rows project to `unlabeled`); `systemMessageSubject` // is nullable (null = no thread subject, e.g. an `unlabeled` legacy row). diff --git a/packages/templates/src/generated/plugin-sdk-dts.generated.ts b/packages/templates/src/generated/plugin-sdk-dts.generated.ts index f66244dbe8..7bf12ff392 100644 --- a/packages/templates/src/generated/plugin-sdk-dts.generated.ts +++ b/packages/templates/src/generated/plugin-sdk-dts.generated.ts @@ -2,6 +2,6 @@ // Generated by packages/templates/scripts/generate-templates.mjs from // @bb/plugin-sdk/bundled-types. Do not edit directly. -export const PLUGIN_SDK_DTS = "// Portable type declarations for `@bb/plugin-sdk`. Unpublished BB\n// workspace contracts are flattened; public subpaths may reuse the\n// package root without requiring any other @bb/* package.\n//\n// Confused by the API, or need a symbol that isn't here? Clone the BB repo\n// and read the real source: https://github.com/ymichael/bb\n\nimport { ComponentType } from 'react';\nimport Database from 'better-sqlite3';\nimport { Context } from 'hono';\nimport * as z from 'zod';\nimport { z as z$1 } from 'zod';\n\n/**\n * A value that survives a JSON round trip without coercion or data loss.\n *\n * Host boundaries still validate values at runtime because TypeScript cannot\n * exclude non-finite numbers and plugin bundles can bypass static types.\n */\ntype JsonValue$1 = string | number | boolean | null | JsonValue$1[] | {\n [key: string]: JsonValue$1;\n};\n\n/** A JSON-safe path segment reported by a Standard Schema validation issue. */\ntype PluginRpcIssuePathSegment = string | number;\n/** Validator-neutral validation detail carried by an RPC error envelope. */\ninterface PluginRpcValidationIssue {\n message: string;\n path?: PluginRpcIssuePathSegment[];\n}\n/** Stable wire error categories for plugin RPC. */\ntype PluginRpcErrorCode = \"invalid_json\" | \"invalid_input\" | \"handler_error\" | \"invalid_output\" | \"non_json_result\" | \"unknown_method\";\n/** Structured RPC failure returned as `{ ok: false, error }`. */\ninterface PluginRpcError {\n code: PluginRpcErrorCode;\n message: string;\n issues?: PluginRpcValidationIssue[];\n}\n/**\n * The validator-neutral subset of Standard Schema v1 used by plugin RPC.\n * Zod 4 schemas implement this interface directly; other validators can do\n * the same without becoming part of BB's public protocol.\n */\ninterface StandardSchemaV1 {\n readonly \"~standard\": {\n readonly version: 1;\n readonly vendor: string;\n readonly validate: (value: unknown) => StandardSchemaV1Result | Promise>;\n readonly types?: {\n readonly input: Input;\n readonly output: Output;\n };\n };\n}\ntype StandardSchemaV1Result = {\n readonly value: Output;\n readonly issues?: undefined;\n} | {\n readonly issues: readonly StandardSchemaV1Issue[];\n};\ninterface StandardSchemaV1Issue {\n readonly message: string;\n readonly path?: PropertyKey | readonly (PropertyKey | {\n readonly key: PropertyKey;\n })[];\n}\ntype StandardSchemaV1InferInput = NonNullable[\"input\"];\ntype StandardSchemaV1InferOutput = NonNullable[\"output\"];\ninterface PluginRpcMethodContract {\n readonly input: InputSchema;\n readonly output: OutputSchema;\n}\ntype PluginRpcContract = Readonly>;\n/** Define a shared RPC contract while preserving exact method/schema types. */\ndeclare function defineRpcContract(contract: Contract): Contract;\ntype PluginRpcHandlers = {\n [Method in keyof Contract]: (input: StandardSchemaV1InferOutput) => StandardSchemaV1InferInput | Promise>;\n};\ntype PluginRpcCallInput = StandardSchemaV1InferInput;\ntype PluginRpcCallArgs = null extends PluginRpcCallInput ? [input?: PluginRpcCallInput] : [input: PluginRpcCallInput];\ntype PluginRpcResult = StandardSchemaV1InferOutput;\n\n/**\n * The `@bb/plugin-sdk/app` contract (plugin design §5.2) — pure types with no\n * side effects. The BB app imports these to keep its real implementation in\n * sync (`satisfies PluginSdkApp`). Plugin authors import the same shapes through\n * `@bb/plugin-sdk/app`.\n *\n * Per-slot props are versioned contracts: additive-only within an SDK major.\n */\n/** Props passed to a `homepageSection` component. */\ninterface PluginHomepageSectionProps {\n /** Project in view on the compose surface; null when none is selected. */\n projectId: string | null;\n}\n/**\n * Props passed to a `settingsSection` component.\n *\n * Deliberately empty in V1; versioned additive like the other slot props.\n */\ninterface PluginSettingsSectionProps {\n}\n/** Props passed to a `navPanel` component (it owns its whole route). */\ninterface PluginNavPanelProps {\n /**\n * The route remainder after the panel root, \"\" at the root. The panel's\n * route is `/plugins///*`, so a deep link like\n * `/plugins/notes/notes/work/ideas.md` renders the panel with\n * `subPath: \"work/ideas.md\"`. Navigate within the panel via\n * `useBbNavigate().toPluginPanel(path, { subPath })` — browser\n * back/forward then walks panel-internal history.\n */\n subPath: string;\n}\n/** Props passed to a panel tab opened by a `threadPanelAction`. */\ninterface PluginThreadPanelProps {\n threadId: string;\n /**\n * The JSON value the action's `openPanel` call passed (round-tripped\n * through persistence, so the tab restores across reloads); null when the\n * action opened the panel without params.\n */\n params: JsonValue$1 | null;\n}\n/** Props passed to a `composerAccessory` component. */\ninterface PluginComposerAccessoryProps {\n projectId: string | null;\n threadId: string | null;\n}\ninterface PluginPendingInteractionView {\n id: string;\n threadId: string;\n title: string;\n payload: JsonValue$1;\n createdAt: number;\n expiresAt: number | null;\n}\ninterface PluginPendingInteractionProps {\n interaction: PluginPendingInteractionView;\n submit(value: JsonValue$1): Promise;\n cancel(): Promise;\n}\n/**\n * Props for a `sidebarFooterAction` — host-rendered (no plugin component).\n * Deliberately empty; the registration's `run` carries the behavior.\n */\ninterface PluginSidebarFooterActionProps {\n}\n/**\n * Where a file being opened by a `fileOpener` lives. `path` semantics follow\n * the source: workspace paths are relative to the environment's worktree,\n * thread-storage paths are relative to the thread's storage root, host paths\n * are absolute on the thread's host.\n */\ninterface PluginFileOpenerSource {\n kind: \"workspace\" | \"host\" | \"thread-storage\";\n threadId: string | null;\n environmentId: string | null;\n projectId: string | null;\n}\n/** Props passed to a `fileOpener` component (rendered as a panel file tab). */\ninterface PluginFileOpenerProps {\n path: string;\n source: PluginFileOpenerSource;\n}\n/**\n * Message context passed to a `messageDirective` component — the assistant\n * (or nested agent) message that contained the directive.\n */\ninterface PluginMessageDirectiveMessage {\n id: string;\n threadId: string;\n turnId: string | null;\n projectId: string | null;\n}\n/**\n * Open a worktree-relative file in the host's workspace file viewer. Returns\n * true when the host accepted the path; false when the path is invalid or the\n * viewer declined it.\n */\ntype PluginMessageDirectiveOpenWorkspaceFile = (path: string) => boolean;\ninterface PluginMessageDirectiveThreadPanelOptions {\n /** A `threadPanelAction` id registered by this same plugin. */\n actionId: string;\n title?: string;\n params?: JsonValue$1;\n}\n/** Open this plugin's registered action in the current thread side panel. */\ntype PluginMessageDirectiveOpenThreadPanel = (options: PluginMessageDirectiveThreadPanelOptions) => boolean;\n/**\n * Props passed to a `messageDirective` component. Attributes are untrusted\n * strings parsed from the directive; the plugin validates its own fields.\n */\ninterface PluginMessageDirectiveProps {\n /** Parsed, untrusted directive attributes (e.g. `{ file: \"demo.html\" }`). */\n attributes: Readonly>;\n /** Original directive source text (useful for diagnostics / crash fallback). */\n source: string;\n message: PluginMessageDirectiveMessage;\n /**\n * Opens a worktree-relative file in the host's workspace file viewer. Null\n * when the message surface has no workspace viewer available.\n */\n openWorkspaceFile: PluginMessageDirectiveOpenWorkspaceFile | null;\n /**\n * Opens one of this plugin's own `threadPanelAction` components in the\n * current thread side panel. Omitted by older hosts; null on message\n * surfaces without a thread panel.\n */\n openThreadPanel?: PluginMessageDirectiveOpenThreadPanel | null;\n}\ninterface PluginHomepageSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n component: ComponentType;\n}\ninterface PluginSettingsSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Optional host-rendered section heading. */\n title?: string;\n /**\n * Optional one-line host-rendered subheading under `title`, in the built-in\n * SettingsSection idiom (ignored when `title` is absent).\n */\n description?: string;\n component: ComponentType;\n}\ninterface PluginNavPanelRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /** URL segment under `/plugins//`; letters, digits, `-`, `_`. */\n path: string;\n component: ComponentType;\n /**\n * Optional component rendered on the right side of the shared title bar\n * (e.g. a sync button or a count). Contained separately from the body: a\n * throwing headerContent is hidden without breaking the title bar.\n */\n headerContent?: ComponentType;\n}\n/** Context handed to a `threadPanelAction`'s `run`. */\ninterface PluginThreadPanelActionContext {\n /** The thread whose panel launcher invoked the action. */\n threadId: string;\n /**\n * Open a tab in the thread's side panel rendering this action's\n * `component`. `title` labels the tab (default: the action's `title`);\n * `params` must be JSON-serializable — it is persisted with the tab and\n * reaches the component as its `params` prop. Opening with params\n * identical to an already-open tab of this action focuses that tab\n * (updating its title) instead of duplicating it. May be called more than\n * once (different params ⇒ multiple tabs) or not at all.\n */\n openPanel(options?: {\n title?: string;\n params?: JsonValue$1;\n }): void;\n}\ninterface PluginThreadPanelActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label of the action row in the panel's new-tab launcher. */\n title: string;\n /**\n * Icon hint (BB icon name) used when the plugin ships no logo; the\n * launcher row and opened tabs prefer the plugin's logo.\n */\n icon?: string;\n /** Rendered inside every panel tab this action opens. */\n component: ComponentType;\n /**\n * Runs when the user activates the action: call your RPC methods, show a\n * toast, and/or open panel tabs via `context.openPanel`. Omitted =\n * immediately open a panel tab with defaults. Errors (sync or async) are\n * contained and logged; they never break the launcher.\n */\n run?(context: PluginThreadPanelActionContext): void | Promise;\n}\ninterface PluginComposerAccessoryRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n component: ComponentType;\n}\ninterface PluginPendingInteractionRegistration {\n /** Matches `rendererId` passed to `bb.ui.requestInput`. */\n id: string;\n component: ComponentType;\n}\n/** Context handed to a `sidebarFooterAction`'s `run`. */\ninterface PluginSidebarFooterActionContext {\n /**\n * Navigate to this plugin's Settings detail page\n * (`/settings/plugins/`), where declarative settings and\n * `settingsSection` slots render.\n */\n openSettings(): void;\n}\n/**\n * An icon button in the app sidebar footer (next to Settings / bug report).\n * Host-rendered for consistent chrome — plugins supply icon, label, and\n * `run` behavior only.\n */\ninterface PluginSidebarFooterActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Tooltip and accessible label for the icon button. */\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /**\n * Runs when the user activates the action (e.g. call `openSettings()`,\n * open a panel via other surfaces, toast). Errors (sync or async) are\n * contained and logged; they never break the sidebar.\n */\n run(context: PluginSidebarFooterActionContext): void | Promise;\n}\n/**\n * Register this plugin as a viewer/editor for file extensions. The user\n * picks (and can set as default) an opener per extension via the file tab's\n * \"Open with\" menu; matching files opened in the panel then render\n * `component` in a plugin tab instead of the built-in preview. Applies to\n * working-tree, host, and thread-storage files — never to git-ref snapshots\n * (diff views always use the built-in preview). The built-in preview stays\n * one menu click away, and a missing/disabled opener falls back to it.\n */\ninterface PluginFileOpenerRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label in the \"Open with\" menu (e.g. \"Notes editor\"). */\n title: string;\n /** Lowercase extensions without the dot (e.g. [\"md\", \"mdx\"]). */\n extensions: readonly string[];\n component: ComponentType;\n}\n/**\n * Register a leaf message directive rendered inside assistant (and nested\n * agent) message Markdown. `id` is the directive name: `inline-vis` matches\n * `::inline-vis{file=\"demo.html\"}`.\n */\ninterface PluginMessageDirectiveRegistration {\n /**\n * The directive name. Lowercase kebab-case beginning with a letter.\n */\n id: string;\n component: ComponentType;\n}\ninterface PluginAppSlots {\n homepageSection(registration: PluginHomepageSectionRegistration): void;\n settingsSection(registration: PluginSettingsSectionRegistration): void;\n navPanel(registration: PluginNavPanelRegistration): void;\n threadPanelAction(registration: PluginThreadPanelActionRegistration): void;\n composerAccessory(registration: PluginComposerAccessoryRegistration): void;\n pendingInteraction(registration: PluginPendingInteractionRegistration): void;\n sidebarFooterAction(registration: PluginSidebarFooterActionRegistration): void;\n fileOpener(registration: PluginFileOpenerRegistration): void;\n messageDirective(registration: PluginMessageDirectiveRegistration): void;\n}\ninterface PluginAppBuilder {\n slots: PluginAppSlots;\n}\ntype PluginAppSetup = (app: PluginAppBuilder) => void;\n/**\n * The opaque product of `definePluginApp` — a plugin's `app.tsx` default\n * export. The host re-runs `setup` against a fresh collector on every\n * (re)interpretation, replacing that plugin's registrations wholesale.\n */\ninterface PluginAppDefinition {\n /** Brand the host checks before interpreting a bundle's default export. */\n readonly __bbPluginApp: true;\n readonly setup: PluginAppSetup;\n}\ninterface PluginRpcClient {\n /**\n * Invoke one of the plugin's `bb.rpc` methods (POST\n * /api/v1/plugins/<id>/rpc/<method>). Resolves with the method's\n * inferred output; rejects with an `Error` carrying the server's message,\n * stable `code`, and validation `issues` when present.\n */\n call>(method: Method, ...args: PluginRpcCallArgs): Promise>;\n}\ninterface PluginSettingsState {\n /**\n * Effective non-secret setting values (secret settings are excluded —\n * read them server-side). Undefined while loading or unavailable.\n */\n values: Record | undefined;\n isLoading: boolean;\n}\n/** State of the app's shared realtime connection to the bb server. */\ntype PluginRealtimeConnectionState = \"connecting\" | \"connected\" | \"reconnecting\";\n/** Where `useComposer()` writes: the active thread's draft or the new-thread draft. */\ntype PluginComposerScope = {\n kind: \"thread\";\n threadId: string;\n} | {\n kind: \"new-thread\";\n projectId: string | null;\n};\n/** An @-mention pill bound to one of the calling plugin's mention providers. */\ninterface PluginComposerMention {\n /** Mention provider id registered by THIS plugin via `bb.ui.registerMentionProvider`. */\n provider: string;\n /** Item id your provider's `resolve` will receive at send time. */\n id: string;\n /** Pill text shown in the composer. */\n label: string;\n}\n/**\n * Programmatic access to the chat composer draft — the same shared draft the\n * built-in \"Add to chat\" affordances (file preview, diff, terminal selections)\n * write to. Inside a thread context writes land in that thread's draft;\n * anywhere else (nav panel, homepage section) they seed the new-thread\n * composer draft, which persists until the user sends or clears it.\n */\ninterface PluginComposerApi {\n scope: PluginComposerScope;\n /** Current plain text for this composer scope. */\n readonly text: string;\n /**\n * Replace the draft's plain text. Attachments are preserved. Inline mentions\n * outside the changed range are preserved and rebased; mentions overlapped\n * by the replacement are removed because their text representation changed.\n */\n setText(next: string): void;\n /**\n * Replace the draft's plain text from the latest committed value. Uses the\n * same structured-state reconciliation as `setText`.\n */\n updateText(updater: (current: string) => string): void;\n /** Clear plain text without clearing independently attached files. */\n clear(): void;\n /**\n * Append text to the draft as a `> ` blockquote block and focus the\n * composer. Blank text is a no-op. This is the \"reference this selection\n * in chat\" primitive.\n */\n addQuote(text: string): void;\n /**\n * Insert an @-mention pill that resolves through this plugin's mention\n * provider at send time — the durable way to reference an entity whose\n * content should be fetched fresh when the message is sent.\n */\n insertMention(mention: PluginComposerMention): void;\n /** Focus the composer caret at the end of the draft. */\n focus(): void;\n}\n/** Current app selection, derived from the route. */\ninterface BbContext {\n projectId: string | null;\n threadId: string | null;\n}\ninterface BbNavigate {\n toThread(threadId: string): void;\n toProject(projectId: string): void;\n /**\n * Navigate to one of this plugin's own nav panels by its `path`.\n * `subPath` targets a location inside the panel (the component's\n * `subPath` prop); `replace` swaps the current history entry instead of\n * pushing — use it for redirects so back does not bounce.\n */\n toPluginPanel(path: string, options?: {\n subPath?: string;\n replace?: boolean;\n }): void;\n /**\n * Navigate to the root compose surface (the new-thread screen). Pass\n * `initialPrompt` to seed the composer draft and `focusPrompt` to focus the\n * composer on arrival — the pairing behind \"Create via chat\" style entry\n * points that drop the user into chat with a prefilled prompt.\n */\n toCompose(options?: {\n initialPrompt?: string;\n focusPrompt?: boolean;\n }): void;\n}\n/**\n * Everything `@bb/plugin-sdk/app` resolves to at runtime. The BB app builds\n * the real implementation and `satisfies` this interface; `bb plugin build`\n * shims the specifier to that object on `globalThis.__bbPluginRuntime`.\n */\ninterface PluginSdkApp {\n definePluginApp(setup: PluginAppSetup): PluginAppDefinition;\n useRpc(): PluginRpcClient;\n useRealtime(channel: string, handler: (payload: unknown) => void): void;\n /**\n * Observe the same shared connection that delivers `useRealtime` signals.\n * Use a subsequent transition to `connected` to reconcile server state that\n * may have changed while ephemeral signals could not be delivered. The first\n * connection can transition from `connecting` and is not a reconnection.\n */\n useRealtimeConnectionState(): PluginRealtimeConnectionState;\n useSettings(): PluginSettingsState;\n useBbContext(): BbContext;\n useBbNavigate(): BbNavigate;\n useComposer(): PluginComposerApi;\n}\n\n/**\n * App-wide server-backed preferences.\n * Client-local settings stay in the frontend localStorage helpers instead.\n */\ndeclare const appSettingsSchema: z$1.ZodObject<{\n caffeinate: z$1.ZodBoolean;\n showKeyboardHints: z$1.ZodBoolean;\n showUnhandledProviderEvents: z$1.ZodBoolean;\n codexMemoryEnabled: z$1.ZodBoolean;\n claudeCodeMemoryEnabled: z$1.ZodBoolean;\n codexSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeWorkflowsDisabled: z$1.ZodBoolean;\n}, z$1.core.$strict>;\ntype AppSettings = z$1.infer;\n\ndeclare const appKeybindingOverridesSchema: z$1.ZodArray;\n shortcut: z$1.ZodNullable>;\n}, z$1.core.$strict>>;\ntype AppKeybindingOverrides = z$1.infer;\n\ndeclare const appThemeSchema: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n}, z$1.core.$strip>;\ntype AppTheme = z$1.infer;\n/**\n * The complete appearance selection a client sends when changing the palette\n * and/or favicon tint. The server validates `themeId` (built-in id or an\n * existing custom theme) and resolves the CSS from disk for custom themes.\n * Callers changing only one facet must carry the other facet forward explicitly.\n */\ndeclare const appThemeSelectionSchema: z$1.ZodObject<{\n themeId: z$1.ZodString;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n}, z$1.core.$strip>;\ntype AppThemeSelection = z$1.infer;\n\ndeclare const changedMessageSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"thread\">;\n id: z$1.ZodOptional;\n metadata: z$1.ZodOptional;\n eventTypes: z$1.ZodOptional>>>>;\n hasPendingInteraction: z$1.ZodOptional;\n projectId: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"project\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"environment\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"host\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"system\">;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>], \"entity\">;\ntype ChangedMessage = z$1.infer;\n\ndeclare const environmentSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodNullable;\n projectId: z$1.ZodString;\n hostId: z$1.ZodString;\n path: z$1.ZodNullable;\n managed: z$1.ZodBoolean;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n branchName: z$1.ZodNullable;\n baseBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n mergeBaseBranch: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n ready: \"ready\";\n retiring: \"retiring\";\n destroying: \"destroying\";\n destroyed: \"destroyed\";\n }>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype Environment = z$1.infer;\n\n/**\n * User-opt-in experiments (the Settings → Experiments toggles). Distinct from\n * `FeatureFlags`: flags are operator-set via env at server start, experiments\n * are user-toggled at runtime and persisted server-side so server-owned\n * policy (e.g. skill injection) can honor them.\n *\n * Every experiment defaults to off — opting in is the point.\n */\ndeclare const experimentsSchema: z$1.ZodObject<{\n claudeCodeMockCliTraffic: z$1.ZodBoolean;\n plugins: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype Experiments = z$1.infer;\n\ndeclare const hostSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n type: z$1.ZodEnum<{\n persistent: \"persistent\";\n }>;\n status: z$1.ZodEnum<{\n connected: \"connected\";\n disconnected: \"disconnected\";\n }>;\n lastSeenAt: z$1.ZodNullable;\n lastRejectedProtocolVersion: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype Host = z$1.infer;\n\ninterface JsonObject {\n [key: string]: JsonValue;\n}\ntype JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;\n\ndeclare const pendingInteractionResolutionSchema: z$1.ZodUnion;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n}, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin_submitted\">;\n}, z$1.core.$strip>]>;\ntype PendingInteractionResolution = z$1.infer;\ndeclare const providerPendingInteractionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n origin: z$1.ZodOptional;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n }, z$1.core.$strip>>;\n payload: z$1.ZodUnion;\n subject: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n itemId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n actions: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"listFiles\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"file_change\">;\n itemId: z$1.ZodString;\n writeScope: z$1.ZodNullable;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>], \"kind\">;\n reason: z$1.ZodNullable;\n availableDecisions: z$1.ZodArray>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>;\n resolution: z$1.ZodNullable;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>>;\n}, z$1.core.$strip>;\ntype ProviderPendingInteraction = z$1.infer;\ndeclare const pluginPendingInteractionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodNullable;\n origin: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n rendererId: z$1.ZodString;\n }, z$1.core.$strip>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n title: z$1.ZodString;\n data: z$1.ZodType>;\n }, z$1.core.$strip>;\n resolution: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginPendingInteraction = z$1.infer;\ntype PendingInteraction = ProviderPendingInteraction | PluginPendingInteraction;\n\ndeclare const projectSourceSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n isDefault: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n type: z$1.ZodLiteral<\"local_path\">;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ProjectSource = z$1.infer;\n\ndeclare const resolvedThreadExecutionOptionsSchema: z$1.ZodObject<{\n seq: z$1.ZodOptional;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n source: z$1.ZodEnum<{\n \"client/thread/start\": \"client/thread/start\";\n \"client/turn/requested\": \"client/turn/requested\";\n \"client/turn/start\": \"client/turn/start\";\n }>;\n}, z$1.core.$strip>;\ntype ResolvedThreadExecutionOptions = z$1.infer;\ndeclare const projectExecutionDefaultsSchema: z$1.ZodObject<{\n providerId: z$1.ZodString;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n}, z$1.core.$strip>;\ntype ProjectExecutionDefaults = z$1.infer;\n\n/** All thread events — provider-originated or system-originated. */\ndeclare const threadEventSchema: z$1.ZodPipe;\n threadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/identity\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/started\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n error: z$1.ZodOptional>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/input/accepted\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n clientRequestId: z$1.ZodString;\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/name/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n threadName: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/compacted\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/goal/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n objective: z$1.ZodString;\n status: z$1.ZodEnum<{\n paused: \"paused\";\n active: \"active\";\n budgetLimited: \"budgetLimited\";\n complete: \"complete\";\n }>;\n tokenBudget: z$1.ZodNullable;\n tokensUsed: z$1.ZodNumber;\n timeUsedSeconds: z$1.ZodNumber;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/goal/cleared\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/started\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"userMessage\">;\n id: z$1.ZodString;\n content: z$1.ZodArray;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n clientRequestId: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"agentMessage\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commandExecution\">;\n id: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n aggregatedOutput: z$1.ZodOptional;\n exitCode: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"fileChange\">;\n id: z$1.ZodString;\n changes: z$1.ZodArray;\n movePath: z$1.ZodOptional;\n diff: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webSearch\">;\n id: z$1.ZodString;\n queries: z$1.ZodArray;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webFetch\">;\n id: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"imageView\">;\n id: z$1.ZodString;\n path: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"toolCall\">;\n id: z$1.ZodString;\n server: z$1.ZodOptional;\n tool: z$1.ZodString;\n arguments: z$1.ZodOptional>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n result: z$1.ZodOptional;\n error: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reasoning\">;\n id: z$1.ZodString;\n summary: z$1.ZodArray;\n content: z$1.ZodArray;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"plan\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"contextCompaction\">;\n id: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"userMessage\">;\n id: z$1.ZodString;\n content: z$1.ZodArray;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n clientRequestId: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"agentMessage\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commandExecution\">;\n id: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n aggregatedOutput: z$1.ZodOptional;\n exitCode: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"fileChange\">;\n id: z$1.ZodString;\n changes: z$1.ZodArray;\n movePath: z$1.ZodOptional;\n diff: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webSearch\">;\n id: z$1.ZodString;\n queries: z$1.ZodArray;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webFetch\">;\n id: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"imageView\">;\n id: z$1.ZodString;\n path: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"toolCall\">;\n id: z$1.ZodString;\n server: z$1.ZodOptional;\n tool: z$1.ZodString;\n arguments: z$1.ZodOptional>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n result: z$1.ZodOptional;\n error: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reasoning\">;\n id: z$1.ZodString;\n summary: z$1.ZodArray;\n content: z$1.ZodArray;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"plan\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"contextCompaction\">;\n id: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/agentMessage/delta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/commandExecution/outputDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n reset: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/fileChange/outputDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/reasoning/summaryTextDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/reasoning/textDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/plan/delta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/mcpToolCall/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n message: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/toolCall/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n message: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/backgroundTask/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/backgroundTask/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/tokenUsage/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n tokenUsage: z$1.ZodObject<{\n total: z$1.ZodObject<{\n totalTokens: z$1.ZodNumber;\n inputTokens: z$1.ZodNumber;\n cachedInputTokens: z$1.ZodNumber;\n outputTokens: z$1.ZodNumber;\n reasoningOutputTokens: z$1.ZodNumber;\n }, z$1.core.$strip>;\n last: z$1.ZodObject<{\n totalTokens: z$1.ZodNumber;\n inputTokens: z$1.ZodNumber;\n cachedInputTokens: z$1.ZodNumber;\n outputTokens: z$1.ZodNumber;\n reasoningOutputTokens: z$1.ZodNumber;\n }, z$1.core.$strip>;\n modelContextWindow: z$1.ZodNullable;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/contextWindowUsage/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n contextWindowUsage: z$1.ZodObject<{\n usedTokens: z$1.ZodNullable;\n modelContextWindow: z$1.ZodNullable;\n estimated: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/plan/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n plan: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n explanation: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/diff/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n diff: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/error\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n message: z$1.ZodString;\n detail: z$1.ZodOptional;\n willRetry: z$1.ZodOptional;\n errorInfo: z$1.ZodOptional;\n providerCode: z$1.ZodNullable;\n httpStatusCode: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/warning\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n category: z$1.ZodEnum<{\n deprecation: \"deprecation\";\n config: \"config\";\n general: \"general\";\n }>;\n summary: z$1.ZodOptional;\n details: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/modelFallback\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n originalModel: z$1.ZodString;\n fallbackModel: z$1.ZodString;\n reason: z$1.ZodEnum<{\n refusal: \"refusal\";\n provider: \"provider\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/unhandled\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerId: z$1.ZodString;\n rawType: z$1.ZodString;\n rawEvent: z$1.ZodObject<{\n jsonrpc: z$1.ZodLiteral<\"2.0\">;\n id: z$1.ZodOptional>;\n method: z$1.ZodString;\n params: z$1.ZodOptional>>;\n }, z$1.core.$strip>;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>], \"type\">, z$1.ZodObject<{\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strip>>, z$1.ZodIntersection;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"client/turn/requested\">;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n requestId: z$1.ZodString;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n senderThreadId: z$1.ZodNullable;\n systemMessageKind: z$1.ZodOptional>;\n systemMessageSubject: z$1.ZodOptional;\n threadId: z$1.ZodString;\n threadName: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-batch\">;\n count: z$1.ZodNumber;\n }, z$1.core.$strip>], \"kind\">>>;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-start\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new-turn\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"auto\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"steer\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>], \"kind\">;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n execution: z$1.ZodObject<{\n seq: z$1.ZodOptional;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n source: z$1.ZodEnum<{\n \"client/thread/start\": \"client/thread/start\";\n \"client/turn/requested\": \"client/turn/requested\";\n \"client/turn/start\": \"client/turn/start\";\n }>;\n permissionMode: z$1.ZodEnum<{\n readonly: \"readonly\";\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n \"workspace-write\": \"workspace-write\";\n }>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"client/turn/start\">;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/error\">;\n threadId: z$1.ZodString;\n code: z$1.ZodOptional;\n message: z$1.ZodString;\n detail: z$1.ZodOptional;\n reconnectAttempt: z$1.ZodOptional;\n reconnectTotal: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/manager/user_message\">;\n threadId: z$1.ZodString;\n text: z$1.ZodString;\n toolCallId: z$1.ZodOptional;\n turnId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/thread/interrupted\">;\n threadId: z$1.ZodString;\n reason: z$1.ZodEnum<{\n \"manual-stop\": \"manual-stop\";\n \"host-daemon-restarted\": \"host-daemon-restarted\";\n \"provider-turn-idle\": \"provider-turn-idle\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/operation\">;\n threadId: z$1.ZodString;\n operation: z$1.ZodString;\n status: z$1.ZodString;\n message: z$1.ZodString;\n operationId: z$1.ZodString;\n metadata: z$1.ZodOptional>>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/permissionGrant/lifecycle\">;\n threadId: z$1.ZodString;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n resolution: z$1.ZodDefault;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">>>;\n statusReason: z$1.ZodDefault>;\n subject: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/userQuestion/lifecycle\">;\n threadId: z$1.ZodString;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n resolution: z$1.ZodDefault;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>>;\n statusReason: z$1.ZodDefault>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/thread-provisioning\">;\n threadId: z$1.ZodString;\n provisioningId: z$1.ZodString;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n active: \"active\";\n cancelled: \"cancelled\";\n }>;\n environmentId: z$1.ZodString;\n entries: z$1.ZodArray;\n key: z$1.ZodString;\n text: z$1.ZodString;\n startedAt: z$1.ZodOptional;\n status: z$1.ZodOptional>;\n metadata: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/provider-turn-watchdog\">;\n threadId: z$1.ZodString;\n reason: z$1.ZodLiteral<\"provider-turn-idle\">;\n thresholdMs: z$1.ZodNumber;\n elapsedMs: z$1.ZodNumber;\n activeTurnId: z$1.ZodString;\n activeTurnStartedAt: z$1.ZodNumber;\n lastActivityEventSequence: z$1.ZodNumber;\n lastActivityEventType: z$1.ZodString;\n lastActivityEventAt: z$1.ZodNumber;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodNullable;\n firedAt: z$1.ZodNumber;\n}, z$1.core.$strip>]>, z$1.ZodObject<{\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strip>>]>>;\ntype ThreadEvent = z$1.infer;\ntype ThreadEventType = ThreadEvent[\"type\"];\n\ndeclare const providerInfoSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n displayName: z$1.ZodString;\n logoUrl: z$1.ZodNullable;\n capabilities: z$1.ZodObject<{\n supportsArchive: z$1.ZodBoolean;\n supportsRename: z$1.ZodBoolean;\n supportsServiceTier: z$1.ZodBoolean;\n supportsUserQuestion: z$1.ZodBoolean;\n supportsFork: z$1.ZodBoolean;\n supportedPermissionModes: z$1.ZodArray>;\n }, z$1.core.$strip>;\n composerActions: z$1.ZodArray;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plan\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"goal\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>], \"kind\">>;\n available: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype ProviderInfo = z$1.infer;\n\ndeclare const threadEventScopeSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n}, z$1.core.$strip>], \"kind\">;\ntype ThreadEventScope = z$1.infer;\n\ntype ThreadEventByType = {\n [TType in ThreadEventType]: Extract;\n};\ntype ThreadEventForType = ThreadEventByType[TType];\ntype StoredThreadEventDataFromEvent = Omit;\ninterface ThreadEventRowBase {\n id: string;\n scope: ThreadEventScope;\n threadId: string;\n seq: number;\n createdAt: number;\n}\ntype ThreadEventRowFromEvent = ThreadEventRowBase & {\n type: TEvent[\"type\"];\n data: StoredThreadEventDataFromEvent;\n};\ntype ThreadEventRowOfType = ThreadEventRowFromEvent>;\ntype ThreadEventRow = {\n [TType in ThreadEventType]: ThreadEventRowOfType;\n}[ThreadEventType];\n\ndeclare const threadStatusSchema: z$1.ZodEnum<{\n error: \"error\";\n active: \"active\";\n starting: \"starting\";\n idle: \"idle\";\n stopping: \"stopping\";\n}>;\ntype ThreadStatus = z$1.infer;\n\ndeclare const threadTimelinePendingTodosSchema: z$1.ZodObject<{\n sourceSeq: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n items: z$1.ZodArray;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ThreadTimelinePendingTodos = z$1.infer;\n\ndeclare const threadQueuedMessageSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n content: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadQueuedMessage = z$1.infer;\n\ndeclare const workspaceFileListResponseSchema: z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype WorkspaceFileListResponse = z$1.infer;\ndeclare const workspacePathListResponseSchema: z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype WorkspacePathListResponse = z$1.infer;\n\ndeclare const createProjectSourceRequestSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodPipe>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"clone\">;\n targetPath: z$1.ZodOptional>>;\n remoteUrl: z$1.ZodOptional;\n}, z$1.core.$strict>], \"type\">;\ntype CreateProjectSourceRequest = z$1.infer;\ndeclare const createProjectRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n source: z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodPipe>;\n }, z$1.core.$strict>;\n}, z$1.core.$strip>;\ntype CreateProjectRequest = z$1.infer;\ndeclare const threadSectionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadSectionResponse = z$1.infer;\ndeclare const createThreadSectionRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype CreateThreadSectionRequest = z$1.infer;\ndeclare const updateThreadSectionRequestSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateThreadSectionRequest = z$1.infer;\ndeclare const deleteThreadSectionRequestSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n}, z$1.core.$strict>;\ntype DeleteThreadSectionRequest = z$1.infer;\ndeclare const threadSectionMutationResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n updatedThreadCount: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadSectionMutationResponse = z$1.infer;\ndeclare const reorderProjectRequestSchema: z$1.ZodObject<{\n previousProjectId: z$1.ZodNullable;\n nextProjectId: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ReorderProjectRequest = z$1.infer;\ndeclare const projectListQuerySchema: z$1.ZodObject<{\n include: z$1.ZodOptional;\n includePersonal: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype ProjectListQuery = z$1.infer;\ndeclare const projectFilesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional>;\n limit: z$1.ZodOptional>;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectFilesQuery = z$1.infer;\ndeclare const projectPathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional>;\n limit: z$1.ZodOptional>;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectPathsQuery = z$1.infer;\ndeclare const projectFileContentQuerySchema: z$1.ZodObject<{\n path: z$1.ZodString;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectFileContentQuery = z$1.infer;\ndeclare const projectBranchesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n hostId: z$1.ZodString;\n selectedBranch: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ProjectBranchesQuery = z$1.infer;\ndeclare const projectBranchesResponseSchema: z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n defaultBranch: z$1.ZodNullable;\n defaultBranchRelation: z$1.ZodNullable>;\n hasUncommittedChanges: z$1.ZodBoolean;\n operation: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"none\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"rebase\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"cherry-pick\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"revert\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>], \"kind\">;\n originDefaultBranch: z$1.ZodNullable;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n defaultWorktreeBaseBranch: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ProjectBranchesResponse = z$1.infer;\ndeclare const promptHistoryQuerySchema: z$1.ZodObject<{\n limit: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PromptHistoryQuery = z$1.infer;\ndeclare const promptHistoryResponseSchema: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>>;\ntype PromptHistoryResponse = z$1.infer;\ndeclare const updateProjectRequestSchema: z$1.ZodObject<{\n name: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype UpdateProjectRequest = z$1.infer;\ndeclare const updateProjectSourceRequestSchema: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodOptional>>;\n isDefault: z$1.ZodOptional>;\n}, z$1.core.$strict>;\ntype UpdateProjectSourceRequest = z$1.infer;\ndeclare const commandListResponseSchema: z$1.ZodObject<{\n commands: z$1.ZodArray;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n description: z$1.ZodNullable;\n argumentHint: z$1.ZodNullable;\n pluginId: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype CommandListResponse = z$1.infer;\n/** Query for the complete command catalog available to a project and provider. */\ndeclare const projectCommandsQuerySchema: z$1.ZodObject<{\n provider: z$1.ZodString;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strict>;\ntype ProjectCommandsQuery = z$1.infer;\ndeclare const projectResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodEnum<{\n personal: \"personal\";\n standard: \"standard\";\n }>;\n name: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n sources: z$1.ZodArray;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ProjectResponse = z$1.infer;\ndeclare const projectWithThreadsResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodEnum<{\n personal: \"personal\";\n standard: \"standard\";\n }>;\n name: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n sources: z$1.ZodArray;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n threads: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>>;\n defaultExecutionOptions: z$1.ZodNullable;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ProjectWithThreadsResponse = z$1.infer;\ndeclare const uploadedPromptAttachmentSchema: z$1.ZodObject<{\n type: z$1.ZodEnum<{\n localImage: \"localImage\";\n localFile: \"localFile\";\n }>;\n path: z$1.ZodString;\n name: z$1.ZodString;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype UploadedPromptAttachment = z$1.infer;\ndeclare const copyProjectAttachmentsRequestSchema: z$1.ZodObject<{\n sourceProjectId: z$1.ZodString;\n paths: z$1.ZodArray;\n}, z$1.core.$strict>;\ntype CopyProjectAttachmentsRequest = z$1.infer;\n\ndeclare const updateEnvironmentRequestSchema: z$1.ZodObject<{\n mergeBaseBranch: z$1.ZodOptional>;\n name: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype UpdateEnvironmentRequest = z$1.infer;\n/**\n * Query for searching paths in an environment's workspace. Unlike the\n * project-scoped variant this needs no `environmentId` — the environment is\n * the route param — and is project-agnostic, so it works for projectless\n * (personal) environments too.\n */\ndeclare const environmentPathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n}, z$1.core.$strip>;\ntype EnvironmentPathsQuery = z$1.infer;\ndeclare const environmentDiffBranchesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n selectedBranch: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype EnvironmentDiffBranchesQuery = z$1.infer;\ndeclare const environmentDiffBranchesResponseSchema: z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype EnvironmentDiffBranchesResponse = z$1.infer;\ndeclare const environmentStatusQuerySchema: z$1.ZodObject<{\n mergeBaseBranch: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype EnvironmentStatusQuery = z$1.infer;\ndeclare const environmentDiffQuerySchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n target: z$1.ZodLiteral<\"uncommitted\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodPipe;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodPipe;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n}, z$1.core.$strip>], \"target\">;\ntype EnvironmentDiffQuery = z$1.infer;\n/**\n * Query for fetching a single file's contents at one side of a diff target.\n * Used by the diff card to reparse the card's patch with full old/new contents\n * so `@pierre/diffs` can render expand-context buttons between hunks.\n *\n * For `branch_committed` / `all`, callers pass the resolved merge-base SHA\n * (`mergeBaseRef`, surfaced by `workspace.diff`) rather than the branch name\n * — the diff itself was computed against that SHA, so reading the old side\n * from the same SHA keeps the file content aligned with the hunk line\n * numbers. Reading from the branch tip is wrong whenever the branch has\n * moved past the merge-base since the file existed there.\n */\ndeclare const environmentDiffFileQuerySchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n target: z$1.ZodLiteral<\"uncommitted\">;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseRef: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"all\">;\n mergeBaseRef: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>], \"target\">;\ntype EnvironmentDiffFileQuery = z$1.infer;\ndeclare const environmentDiffFileResponseSchema: z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype EnvironmentDiffFileResponse = z$1.infer;\ndeclare const environmentArchiveThreadsResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n archivedThreadIds: z$1.ZodArray;\n}, z$1.core.$strip>;\ntype EnvironmentArchiveThreadsResponse = z$1.infer;\ndeclare const pullRequestMergeMethodSchema: z$1.ZodEnum<{\n merge: \"merge\";\n rebase: \"rebase\";\n squash: \"squash\";\n}>;\ntype PullRequestMergeMethod = z$1.infer;\ndeclare const commitActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"commit\">;\n message: z$1.ZodString;\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n}, z$1.core.$strip>;\ntype CommitActionResponse = z$1.infer;\ndeclare const squashMergeActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"squash_merge\">;\n merged: z$1.ZodBoolean;\n message: z$1.ZodString;\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SquashMergeActionResponse = z$1.infer;\ndeclare const pullRequestReadyActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_ready\">;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestReadyActionResponse = z$1.infer;\ndeclare const pullRequestMergeActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_merge\">;\n method: z$1.ZodEnum<{\n merge: \"merge\";\n rebase: \"rebase\";\n squash: \"squash\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestMergeActionResponse = z$1.infer;\ndeclare const pullRequestDraftActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_draft\">;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestDraftActionResponse = z$1.infer;\ndeclare const environmentStatusResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n workspace: z$1.ZodObject<{\n workingTree: z$1.ZodObject<{\n insertions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n files: z$1.ZodArray;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n hasUncommittedChanges: z$1.ZodBoolean;\n state: z$1.ZodEnum<{\n clean: \"clean\";\n untracked: \"untracked\";\n dirty_uncommitted: \"dirty_uncommitted\";\n committed_unmerged: \"committed_unmerged\";\n dirty_and_committed_unmerged: \"dirty_and_committed_unmerged\";\n }>;\n }, z$1.core.$strip>;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n branch: z$1.ZodObject<{\n currentBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodString;\n }, z$1.core.$strip>;\n mergeBase: z$1.ZodNullable;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n mergeBaseBranch: z$1.ZodString;\n baseRef: z$1.ZodNullable;\n aheadCount: z$1.ZodNumber;\n behindCount: z$1.ZodNumber;\n hasCommittedUnmergedChanges: z$1.ZodBoolean;\n commits: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\n/**\n * Structured pull-request lookup outcome. \"absent\" is a real answer — the\n * host checked and the branch has no PR (non-git environments resolve to\n * \"absent\" without a daemon call). \"unavailable\" means the lookup itself\n * failed (gh missing, not authenticated, timeout, unreachable workspace), so\n * callers must not render it as \"no PR exists\".\n */\ndeclare const environmentPullRequestResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n pullRequest: z$1.ZodObject<{\n number: z$1.ZodNumber;\n title: z$1.ZodString;\n state: z$1.ZodEnum<{\n merged: \"merged\";\n draft: \"draft\";\n open: \"open\";\n closed: \"closed\";\n }>;\n url: z$1.ZodString;\n baseRefName: z$1.ZodString;\n headRefName: z$1.ZodString;\n updatedAt: z$1.ZodString;\n checks: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n unknown: \"unknown\";\n pending: \"pending\";\n passing: \"passing\";\n failing: \"failing\";\n no_checks: \"no_checks\";\n }>;\n totalCount: z$1.ZodNumber;\n passedCount: z$1.ZodNumber;\n failedCount: z$1.ZodNumber;\n pendingCount: z$1.ZodNumber;\n }, z$1.core.$strict>;\n review: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n none: \"none\";\n approved: \"approved\";\n changes_requested: \"changes_requested\";\n review_required: \"review_required\";\n review_requested: \"review_requested\";\n }>;\n reviewRequestCount: z$1.ZodNumber;\n }, z$1.core.$strict>;\n mergeability: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n unknown: \"unknown\";\n draft: \"draft\";\n mergeable: \"mergeable\";\n conflicts: \"conflicts\";\n blocked: \"blocked\";\n }>;\n mergeStateStatus: z$1.ZodNullable>;\n mergeable: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n attention: z$1.ZodEnum<{\n none: \"none\";\n merged: \"merged\";\n draft: \"draft\";\n closed: \"closed\";\n changes_requested: \"changes_requested\";\n review_requested: \"review_requested\";\n conflicts: \"conflicts\";\n blocked: \"blocked\";\n checks_failed: \"checks_failed\";\n checks_pending: \"checks_pending\";\n ready_to_merge: \"ready_to_merge\";\n }>;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"absent\">;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n message: z$1.ZodString;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentPullRequestResponse = z$1.infer;\ndeclare const environmentDiffResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n diff: z$1.ZodObject<{\n diff: z$1.ZodString;\n truncated: z$1.ZodBoolean;\n shortstat: z$1.ZodString;\n files: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strip>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffResponse = z$1.infer;\ndeclare const environmentDiffFilesResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n files: z$1.ZodArray;\n changeKind: z$1.ZodEnum<{\n deleted: \"deleted\";\n added: \"added\";\n modified: \"modified\";\n renamed: \"renamed\";\n copied: \"copied\";\n type_changed: \"type_changed\";\n }>;\n additions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n binary: z$1.ZodBoolean;\n origin: z$1.ZodEnum<{\n untracked: \"untracked\";\n tracked: \"tracked\";\n }>;\n loadMode: z$1.ZodEnum<{\n auto: \"auto\";\n on_demand: \"on_demand\";\n too_large: \"too_large\";\n }>;\n }, z$1.core.$strip>>;\n shortstat: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n initialPatches: z$1.ZodArray>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n too_many_files: \"too_many_files\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffFilesResponse = z$1.infer;\ndeclare const environmentDiffPatchResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n patches: z$1.ZodArray>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffPatchResponse = z$1.infer;\n/**\n * Body for `POST /diff/patch`: the diff target plus the list of new paths whose\n * patches the client wants. A POST (not GET) because the repeated `paths` array\n * cannot survive flat query parsing. The client supplies only new paths; the\n * server re-derives each file's rename/copy pairing (`previousPath`) from its\n * own TOC.\n */\ndeclare const environmentDiffPatchRequestSchema: z$1.ZodObject<{\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n paths: z$1.ZodArray;\n}, z$1.core.$strict>;\ntype EnvironmentDiffPatchRequest = z$1.infer;\ntype EnvironmentStatusResponse = z$1.infer;\n\ndeclare const providerUsageResponseSchema: z$1.ZodObject<{\n codex: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n claudeCode: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n cursor: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n}, z$1.core.$strip>;\ntype ProviderUsageResponse = z$1.infer;\ntype HostDaemonCommandTransport = \"settled\" | \"onlineRpc\";\ntype HostDaemonCommandEnvironmentLane = \"read\" | \"write\";\ntype HostDaemonFlushEventsBeforeResult = boolean | \"when-initiated\";\ninterface HostDaemonCommandDescriptor {\n type: Type;\n schema: Schema;\n resultSchema: ResultSchema;\n transport: Transport;\n retryable: Retryable;\n flushEventsBeforeResult: HostDaemonFlushEventsBeforeResult;\n envLane: HostDaemonCommandEnvironmentLane | null;\n}\ndeclare const hostDaemonCommandRegistry: {\n \"thread.start\": HostDaemonCommandDescriptor<\"thread.start\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n projectId: z$1.ZodString;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n options: z$1.ZodIntersection;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n claudeCodePermissionMode: z$1.ZodOptional>;\n claudeCodeMockCliTraffic: z$1.ZodOptional>;\n workflowsEnabled: z$1.ZodBoolean;\n memoryEnabled: z$1.ZodOptional;\n providerSubagentsEnabled: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"accept-edits\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"user\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"auto\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"automatic\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"full\">;\n permissionScope: z$1.ZodLiteral<\"full\">;\n approvalReviewer: z$1.ZodNull;\n permissionEscalation: z$1.ZodNull;\n }, z$1.core.$strip>], \"permissionMode\">>;\n instructions: z$1.ZodString;\n dynamicTools: z$1.ZodArray>;\n injectedSkillSources: z$1.ZodArray;\n treeHash: z$1.ZodString;\n entryPath: z$1.ZodString;\n sourceType: z$1.ZodEnum<{\n builtin: \"builtin\";\n \"data-dir\": \"data-dir\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n name: z$1.ZodString;\n description: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-path\">;\n sourceType: z$1.ZodLiteral<\"project\">;\n sourceRootPath: z$1.ZodString;\n skillFilePath: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n disallowedTools: z$1.ZodOptional>;\n instructionMode: z$1.ZodEnum<{\n append: \"append\";\n replace: \"replace\";\n }>;\n type: z$1.ZodLiteral<\"thread.start\">;\n requestId: z$1.ZodString;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n threadStoragePath: z$1.ZodOptional;\n fork: z$1.ZodOptional>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"turn.submit\": HostDaemonCommandDescriptor<\"turn.submit\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"turn.submit\">;\n requestId: z$1.ZodString;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n options: z$1.ZodIntersection;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n claudeCodePermissionMode: z$1.ZodOptional>;\n claudeCodeMockCliTraffic: z$1.ZodOptional>;\n workflowsEnabled: z$1.ZodBoolean;\n memoryEnabled: z$1.ZodOptional;\n providerSubagentsEnabled: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"accept-edits\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"user\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"auto\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"automatic\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"full\">;\n permissionScope: z$1.ZodLiteral<\"full\">;\n approvalReviewer: z$1.ZodNull;\n permissionEscalation: z$1.ZodNull;\n }, z$1.core.$strip>], \"permissionMode\">>;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n resumeContext: z$1.ZodObject<{\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n instructionMode: z$1.ZodEnum<{\n append: \"append\";\n replace: \"replace\";\n }>;\n projectId: z$1.ZodString;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n instructions: z$1.ZodString;\n dynamicTools: z$1.ZodArray>;\n injectedSkillSources: z$1.ZodArray;\n treeHash: z$1.ZodString;\n entryPath: z$1.ZodString;\n sourceType: z$1.ZodEnum<{\n builtin: \"builtin\";\n \"data-dir\": \"data-dir\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n name: z$1.ZodString;\n description: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-path\">;\n sourceType: z$1.ZodLiteral<\"project\">;\n sourceRootPath: z$1.ZodString;\n skillFilePath: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n disallowedTools: z$1.ZodOptional>;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"start\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"auto\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"steer\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>], \"mode\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n appliedAs: z$1.ZodEnum<{\n steer: \"steer\";\n \"new-turn\": \"new-turn\";\n }>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"thread.stop\": HostDaemonCommandDescriptor<\"thread.stop\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.stop\">;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.rename\": HostDaemonCommandDescriptor<\"thread.rename\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.rename\">;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.archive\": HostDaemonCommandDescriptor<\"thread.archive\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"thread.archive\">;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.unarchive\": HostDaemonCommandDescriptor<\"thread.unarchive\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.unarchive\">;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"interactive.resolve\": HostDaemonCommandDescriptor<\"interactive.resolve\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"interactive.resolve\">;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n resolution: z$1.ZodUnion;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin_submitted\">;\n }, z$1.core.$strip>]>;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"codex.inference.complete\": HostDaemonCommandDescriptor<\"codex.inference.complete\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"codex.inference.complete\">;\n model: z$1.ZodString;\n prompt: z$1.ZodString;\n outputSchema: z$1.ZodType>;\n timeoutMs: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n model: z$1.ZodString;\n value: z$1.ZodType>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"codex.voice.transcribe\": HostDaemonCommandDescriptor<\"codex.voice.transcribe\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"codex.voice.transcribe\">;\n model: z$1.ZodString;\n audioBase64: z$1.ZodString;\n mimeType: z$1.ZodString;\n filename: z$1.ZodString;\n prompt: z$1.ZodNullable;\n timeoutMs: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n model: z$1.ZodString;\n text: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"environment.provision\": HostDaemonCommandDescriptor<\"environment.provision\", z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n workspaceProvisionType: z$1.ZodLiteral<\"unmanaged\">;\n path: z$1.ZodString;\n checkout: z$1.ZodOptional;\n name: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new\">;\n name: z$1.ZodString;\n baseBranch: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n sourcePath: z$1.ZodString;\n targetPath: z$1.ZodString;\n branchName: z$1.ZodString;\n baseBranch: z$1.ZodNullable;\n setupTimeoutMs: z$1.ZodNumber;\n workspaceProvisionType: z$1.ZodLiteral<\"managed-worktree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n workspaceProvisionType: z$1.ZodLiteral<\"personal\">;\n targetPath: z$1.ZodString;\n }, z$1.core.$strict>], \"workspaceProvisionType\">, z$1.ZodObject<{\n path: z$1.ZodString;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n branchName: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n transcript: z$1.ZodArray;\n key: z$1.ZodString;\n text: z$1.ZodString;\n startedAt: z$1.ZodOptional;\n status: z$1.ZodOptional>;\n metadata: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"project.clone\": HostDaemonCommandDescriptor<\"project.clone\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.clone\">;\n remoteUrl: z$1.ZodString;\n projectSlug: z$1.ZodString;\n targetPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n }, z$1.core.$strict>, \"settled\", false>;\n \"environment.provision.cancel\": HostDaemonCommandDescriptor<\"environment.provision.cancel\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision.cancel\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n aborted: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"settled\", false>;\n \"environment.destroy\": HostDaemonCommandDescriptor<\"environment.destroy\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"environment.destroy\">;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"workspace.commit\": HostDaemonCommandDescriptor<\"workspace.commit\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.commit\">;\n message: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"workspace.squash_merge\": HostDaemonCommandDescriptor<\"workspace.squash_merge\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.squash_merge\">;\n targetBranch: z$1.ZodString;\n commitMessage: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n merged: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"settled\", false>;\n \"workspace.pull_request_action\": HostDaemonCommandDescriptor<\"workspace.pull_request_action\", z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"ready\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"draft\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"merge\">;\n method: z$1.ZodEnum<{\n merge: \"merge\";\n squash: \"squash\";\n rebase: \"rebase\";\n }>;\n }, z$1.core.$strict>], \"operation\">, z$1.ZodObject<{}, z$1.core.$strict>, \"settled\", false>;\n \"host.list_files\": HostDaemonCommandDescriptor<\"host.list_files\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_files\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n }, z$1.core.$strip>, z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.list_paths\": HostDaemonCommandDescriptor<\"host.list_paths\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_paths\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n includeFiles: z$1.ZodBoolean;\n includeDirectories: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.mkdir\": HostDaemonCommandDescriptor<\"host.mkdir\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.mkdir\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n recursive: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.move_path\": HostDaemonCommandDescriptor<\"host.move_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.move_path\">;\n sourcePath: z$1.ZodString;\n destinationPath: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.remove_path\": HostDaemonCommandDescriptor<\"host.remove_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.remove_path\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n recursive: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.browse_directory\": HostDaemonCommandDescriptor<\"host.browse_directory\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.browse_directory\">;\n path: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n directory: z$1.ZodString;\n parent: z$1.ZodNullable;\n entries: z$1.ZodArray;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.paths_exist\": HostDaemonCommandDescriptor<\"host.paths_exist\", z$1.ZodObject<{\n paths: z$1.ZodPipe, z$1.ZodTransform>;\n type: z$1.ZodLiteral<\"host.paths_exist\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n existence: z$1.ZodRecord;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"project.inspect\": HostDaemonCommandDescriptor<\"project.inspect\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.inspect\">;\n path: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"project.clone_default_path\": HostDaemonCommandDescriptor<\"project.clone_default_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.clone_default_path\">;\n projectSlug: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"host.pick_folder\": HostDaemonCommandDescriptor<\"host.pick_folder\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.pick_folder\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, \"onlineRpc\", false>;\n \"host.caffeinate\": HostDaemonCommandDescriptor<\"host.caffeinate\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.caffeinate\">;\n enabled: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n enabled: z$1.ZodBoolean;\n supported: z$1.ZodBoolean;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"connect-tunnel.ensure-identity\": HostDaemonCommandDescriptor<\"connect-tunnel.ensure-identity\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"connect-tunnel.ensure-identity\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n label: z$1.ZodString;\n baseDomain: z$1.ZodString;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"host.list_commands\": HostDaemonCommandDescriptor<\"host.list_commands\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_commands\">;\n providerId: z$1.ZodString;\n cwd: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commands: z$1.ZodArray;\n origin: z$1.ZodEnum<{\n project: \"project\";\n user: \"user\";\n }>;\n description: z$1.ZodNullable;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.list_branches\": HostDaemonCommandDescriptor<\"host.list_branches\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_branches\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n selectedBranch: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n }, z$1.core.$strip>, z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n defaultBranch: z$1.ZodNullable;\n defaultBranchRelation: z$1.ZodNullable>;\n hasUncommittedChanges: z$1.ZodBoolean;\n operation: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"none\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"rebase\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"cherry-pick\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"revert\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>], \"kind\">;\n originDefaultBranch: z$1.ZodNullable;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.file_metadata\": HostDaemonCommandDescriptor<\"host.file_metadata\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.file_metadata\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n modifiedAtMs: z$1.ZodNumber;\n sizeBytes: z$1.ZodNumber;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.read_file\": HostDaemonCommandDescriptor<\"host.read_file\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.read_file\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n ref: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n modifiedAtMs: z$1.ZodOptional;\n sha256: z$1.ZodString;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.read_file_relative\": HostDaemonCommandDescriptor<\"host.read_file_relative\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.read_file_relative\">;\n rootPath: z$1.ZodString;\n path: z$1.ZodString;\n dotfiles: z$1.ZodEnum<{\n deny: \"deny\";\n allow: \"allow\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n modifiedAtMs: z$1.ZodOptional;\n sha256: z$1.ZodString;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.write_file\": HostDaemonCommandDescriptor<\"host.write_file\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.write_file\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n createParents: z$1.ZodBoolean;\n expectedSha256: z$1.ZodOptional>;\n mode: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"written\">;\n sha256: z$1.ZodString;\n sizeBytes: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"conflict\">;\n currentSha256: z$1.ZodNullable;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", false>;\n \"provider.list_models\": HostDaemonCommandDescriptor<\"provider.list_models\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider.list_models\">;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n models: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n selectedOnlyModels: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"known_acp_agents.status\": HostDaemonCommandDescriptor<\"known_acp_agents.status\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"known_acp_agents.status\">;\n agents: z$1.ZodArray>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n agents: z$1.ZodArray;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"provider.usage\": HostDaemonCommandDescriptor<\"provider.usage\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider.usage\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n codex: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n claudeCode: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n cursor: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"provider_cli.status\": HostDaemonCommandDescriptor<\"provider_cli.status\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider_cli.status\">;\n }, z$1.core.$strict>, z$1.ZodRecord, z$1.ZodObject<{\n displayName: z$1.ZodString;\n executableName: z$1.ZodString;\n executablePath: z$1.ZodNullable;\n installed: z$1.ZodBoolean;\n installSource: z$1.ZodEnum<{\n external: \"external\";\n notInstalled: \"notInstalled\";\n npmGlobal: \"npmGlobal\";\n }>;\n currentVersion: z$1.ZodNullable;\n latestVersion: z$1.ZodNullable;\n minimumSupportedVersion: z$1.ZodNullable;\n npmPackageName: z$1.ZodNullable;\n npmGlobalPackageVersion: z$1.ZodNullable;\n installAction: z$1.ZodNullable;\n label: z$1.ZodEnum<{\n Install: \"Install\";\n Update: \"Update\";\n }>;\n commandKind: z$1.ZodEnum<{\n exec: \"exec\";\n shell: \"shell\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>>;\n needsUpdate: z$1.ZodBoolean;\n versionUnsupported: z$1.ZodBoolean;\n }, z$1.core.$strip>>, \"onlineRpc\", true>;\n \"provider_cli.install\": HostDaemonCommandDescriptor<\"provider_cli.install\", z$1.ZodObject<{\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n actionKind: z$1.ZodEnum<{\n install: \"install\";\n update: \"update\";\n }>;\n type: z$1.ZodLiteral<\"provider_cli.install\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n events: z$1.ZodArray;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"output\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n stream: z$1.ZodEnum<{\n stdout: \"stdout\";\n stderr: \"stderr\";\n }>;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"completed\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n exitCode: z$1.ZodNullable;\n signal: z$1.ZodNullable;\n success: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"error\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"workspace.status\": HostDaemonCommandDescriptor<\"workspace.status\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.status\">;\n mergeBaseBranch: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n workspaceStatus: z$1.ZodObject<{\n workingTree: z$1.ZodObject<{\n insertions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n files: z$1.ZodArray;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n hasUncommittedChanges: z$1.ZodBoolean;\n state: z$1.ZodEnum<{\n clean: \"clean\";\n untracked: \"untracked\";\n dirty_uncommitted: \"dirty_uncommitted\";\n committed_unmerged: \"committed_unmerged\";\n dirty_and_committed_unmerged: \"dirty_and_committed_unmerged\";\n }>;\n }, z$1.core.$strip>;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n branch: z$1.ZodObject<{\n currentBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodString;\n }, z$1.core.$strip>;\n mergeBase: z$1.ZodNullable;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n mergeBaseBranch: z$1.ZodString;\n baseRef: z$1.ZodNullable;\n aheadCount: z$1.ZodNumber;\n behindCount: z$1.ZodNumber;\n hasCommittedUnmergedChanges: z$1.ZodBoolean;\n commits: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n unknown: \"unknown\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diff\": HostDaemonCommandDescriptor<\"workspace.diff\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diff\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n maxDiffBytes: z$1.ZodNumber;\n maxFileListBytes: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n diff: z$1.ZodObject<{\n diff: z$1.ZodString;\n truncated: z$1.ZodBoolean;\n shortstat: z$1.ZodString;\n files: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strip>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n unknown: \"unknown\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diffFiles\": HostDaemonCommandDescriptor<\"workspace.diffFiles\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diffFiles\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n files: z$1.ZodArray;\n statusLetter: z$1.ZodEnum<{\n M: \"M\";\n A: \"A\";\n D: \"D\";\n R: \"R\";\n C: \"C\";\n T: \"T\";\n }>;\n additions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n binary: z$1.ZodBoolean;\n origin: z$1.ZodEnum<{\n untracked: \"untracked\";\n tracked: \"tracked\";\n }>;\n }, z$1.core.$strip>>;\n shortstat: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n unknown: \"unknown\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diffPatch\": HostDaemonCommandDescriptor<\"workspace.diffPatch\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diffPatch\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n paths: z$1.ZodArray;\n maxBytesPerFile: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n patches: z$1.ZodArray>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n unknown: \"unknown\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.pull_request\": HostDaemonCommandDescriptor<\"workspace.pull_request\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request\">;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n pullRequest: z$1.ZodObject<{\n number: z$1.ZodNumber;\n title: z$1.ZodString;\n state: z$1.ZodEnum<{\n OPEN: \"OPEN\";\n CLOSED: \"CLOSED\";\n MERGED: \"MERGED\";\n }>;\n url: z$1.ZodString;\n isDraft: z$1.ZodBoolean;\n baseRefName: z$1.ZodString;\n headRefName: z$1.ZodString;\n updatedAt: z$1.ZodString;\n checks: z$1.ZodArray;\n conclusion: z$1.ZodNullable>;\n url: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n reviewDecision: z$1.ZodNullable>;\n reviewRequestCount: z$1.ZodNumber;\n mergeStateStatus: z$1.ZodNullable>;\n mergeable: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"absent\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n message: z$1.ZodString;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n};\ntype HostDaemonCommandRegistry = typeof hostDaemonCommandRegistry;\ntype AnyHostDaemonCommandDescriptor = HostDaemonCommandRegistry[keyof HostDaemonCommandRegistry];\ntype HostDaemonCommandDescriptorForTransport = Extract;\ntype HostDaemonResultSchemaMapForTransport = {\n [Descriptor in HostDaemonCommandDescriptorForTransport as Descriptor[\"type\"]]: Descriptor[\"resultSchema\"];\n};\ntype HostDaemonOnlineRpcResultSchemaMap = HostDaemonResultSchemaMapForTransport<\"onlineRpc\">;\ntype HostDaemonOnlineRpcResultByType = {\n [K in keyof HostDaemonOnlineRpcResultSchemaMap]: z$1.infer;\n};\n\ndeclare const pickFolderResponseSchema: z$1.ZodObject<{\n path: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype PickFolderResponse = z$1.infer;\ndeclare const pathsExistRequestSchema: z$1.ZodObject<{\n paths: z$1.ZodPipe, z$1.ZodTransform>;\n}, z$1.core.$strip>;\ntype PathsExistRequest = z$1.infer;\ndeclare const pathsExistResponseSchema: z$1.ZodObject<{\n existence: z$1.ZodRecord;\n}, z$1.core.$strip>;\ntype PathsExistResponse = z$1.infer;\ndeclare const providerCliStatusResponseSchema: z$1.ZodRecord, z$1.ZodObject<{\n displayName: z$1.ZodString;\n executableName: z$1.ZodString;\n executablePath: z$1.ZodNullable;\n installed: z$1.ZodBoolean;\n installSource: z$1.ZodEnum<{\n external: \"external\";\n notInstalled: \"notInstalled\";\n npmGlobal: \"npmGlobal\";\n }>;\n currentVersion: z$1.ZodNullable;\n latestVersion: z$1.ZodNullable;\n minimumSupportedVersion: z$1.ZodNullable;\n npmPackageName: z$1.ZodNullable;\n npmGlobalPackageVersion: z$1.ZodNullable;\n installAction: z$1.ZodNullable;\n label: z$1.ZodEnum<{\n Install: \"Install\";\n Update: \"Update\";\n }>;\n commandKind: z$1.ZodEnum<{\n exec: \"exec\";\n shell: \"shell\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>>;\n needsUpdate: z$1.ZodBoolean;\n versionUnsupported: z$1.ZodBoolean;\n}, z$1.core.$strip>>;\ntype ProviderCliStatusResponse = z$1.infer;\ndeclare const providerCliInstallRequestSchema: z$1.ZodObject<{\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n actionKind: z$1.ZodEnum<{\n install: \"install\";\n update: \"update\";\n }>;\n}, z$1.core.$strip>;\ntype ProviderCliInstallRequest = z$1.infer;\ndeclare const providerCliInstallEventSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"started\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n command: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"output\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n stream: z$1.ZodEnum<{\n stdout: \"stdout\";\n stderr: \"stderr\";\n }>;\n text: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"completed\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n exitCode: z$1.ZodNullable;\n signal: z$1.ZodNullable;\n success: z$1.ZodBoolean;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"error\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>], \"type\">;\ntype ProviderCliInstallEvent = z$1.infer;\n\ninterface CreateFilePreviewResponse {\n baseUrl: string;\n expiresAtMs: number;\n}\ntype HostFileReadResponse = HostDaemonOnlineRpcResultByType[\"host.read_file\"];\ntype HostFileWriteResponse = HostDaemonOnlineRpcResultByType[\"host.write_file\"];\ntype HostFileListResponse = HostDaemonOnlineRpcResultByType[\"host.list_files\"];\ntype HostPathListResponse = HostDaemonOnlineRpcResultByType[\"host.list_paths\"];\ntype HostMkdirResponse = HostDaemonOnlineRpcResultByType[\"host.mkdir\"];\ntype HostMovePathResponse = HostDaemonOnlineRpcResultByType[\"host.move_path\"];\ntype HostRemovePathResponse = HostDaemonOnlineRpcResultByType[\"host.remove_path\"];\n\n/**\n * Query for `GET /hosts/:id/directory`, the interactive path browser's\n * single-level directory read. `path` is an absolute directory on the host;\n * omitting it lists the host's home directory (the daemon resolves it, since a\n * remote caller cannot know the host's home).\n */\ndeclare const hostDirectoryQuerySchema: z$1.ZodObject<{\n path: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype HostDirectoryQuery = z$1.infer;\ndeclare const hostDirectoryListingSchema: z$1.ZodObject<{\n directory: z$1.ZodString;\n parent: z$1.ZodNullable;\n entries: z$1.ZodArray;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype HostDirectoryListing = z$1.infer;\n/** Project name is sent so the daemon can derive its host-local checkout path. */\ndeclare const hostCloneDefaultPathQuerySchema: z$1.ZodObject<{\n projectId: z$1.ZodString;\n}, z$1.core.$strip>;\ntype HostCloneDefaultPathQuery = z$1.infer;\ndeclare const hostCloneDefaultPathResponseSchema: z$1.ZodObject<{\n path: z$1.ZodString;\n}, z$1.core.$strict>;\ntype HostCloneDefaultPathResponse = z$1.infer;\ndeclare const createHostJoinCodeResponseSchema: z$1.ZodObject<{\n joinCode: z$1.ZodString;\n hostId: z$1.ZodString;\n expiresAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype CreateHostJoinCodeResponse = z$1.infer;\ndeclare const updateHostRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateHostRequest = z$1.infer;\ntype HostPathsExistRequest = PathsExistRequest;\ntype HostPathsExistResponse = PathsExistResponse;\ndeclare const hostPickFolderRequestSchema: z$1.ZodObject<{\n clientHostId: z$1.ZodString;\n}, z$1.core.$strict>;\ntype HostPickFolderRequest = z$1.infer;\ntype HostPickFolderResponse = PickFolderResponse;\ntype HostProviderCliStatusResponse = ProviderCliStatusResponse;\ntype HostProviderCliInstallRequest = ProviderCliInstallRequest;\ntype HostProviderCliInstallEvent = ProviderCliInstallEvent;\n\ndeclare const pluginUpdateCheckEntrySchema: z$1.ZodObject<{\n id: z$1.ZodString;\n outcome: z$1.ZodEnum<{\n unavailable: \"unavailable\";\n incompatible: \"incompatible\";\n current: \"current\";\n \"update-available\": \"update-available\";\n pinned: \"pinned\";\n }>;\n devMode: z$1.ZodOptional>;\n installed: z$1.ZodObject<{\n version: z$1.ZodString;\n display: z$1.ZodString;\n }, z$1.core.$strip>;\n candidate: z$1.ZodOptional>;\n blocked: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n detail: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PluginUpdateCheckEntry = z$1.infer;\ndeclare const pluginApplyUpdateResultSchema: z$1.ZodObject<{\n applied: z$1.ZodBoolean;\n from: z$1.ZodObject<{\n version: z$1.ZodString;\n display: z$1.ZodString;\n }, z$1.core.$strip>;\n to: z$1.ZodOptional>;\n outcome: z$1.ZodEnum<{\n current: \"current\";\n updated: \"updated\";\n \"rolled-back\": \"rolled-back\";\n }>;\n detail: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PluginApplyUpdateResult$1 = z$1.infer;\ndeclare const pluginSourceDetailSchema: z$1.ZodObject<{\n requested: z$1.ZodString;\n resolved: z$1.ZodString;\n integrity: z$1.ZodOptional;\n registry: z$1.ZodOptional;\n engines: z$1.ZodObject<{\n bb: z$1.ZodOptional;\n bbPluginSdk: z$1.ZodOptional;\n }, z$1.core.$strip>;\n installedAt: z$1.ZodOptional;\n history: z$1.ZodArray>;\n}, z$1.core.$strip>;\ntype PluginSourceDetail = z$1.infer;\ndeclare const installedPluginSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n source: z$1.ZodString;\n rootDir: z$1.ZodString;\n version: z$1.ZodString;\n provenance: z$1.ZodEnum<{\n builtin: \"builtin\";\n direct: \"direct\";\n catalog: \"catalog\";\n }>;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n missing: \"missing\";\n incompatible: \"incompatible\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype InstalledPlugin = z$1.infer;\ndeclare const pluginListResponseSchema: z$1.ZodObject<{\n enabled: z$1.ZodBoolean;\n plugins: z$1.ZodArray;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n missing: \"missing\";\n incompatible: \"incompatible\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginListResponse = z$1.infer;\ndeclare const pluginReloadResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n plugins: z$1.ZodArray;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n missing: \"missing\";\n incompatible: \"incompatible\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginReloadResponse = z$1.infer;\ndeclare const pluginRemoveResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n}, z$1.core.$strip>;\ntype PluginRemoveResponse = z$1.infer;\ndeclare const pluginSettingsResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n schema: z$1.ZodRecord;\n secret: z$1.ZodOptional>;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"boolean\">;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"select\">;\n options: z$1.ZodArray;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project\">;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>], \"type\">>;\n values: z$1.ZodRecord>>;\n}, z$1.core.$strip>;\ntype PluginSettingsResponse = z$1.infer;\ndeclare const pluginTokenResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n token: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PluginTokenResponse = z$1.infer;\ndeclare const pluginCatalogStatusSchema: z$1.ZodObject<{\n pluginCount: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype PluginCatalogStatus = z$1.infer;\ndeclare const pluginCatalogSearchResultSchema: z$1.ZodObject<{\n entryId: z$1.ZodString;\n displayName: z$1.ZodString;\n description: z$1.ZodString;\n icon: z$1.ZodNullable;\n category: z$1.ZodString;\n source: z$1.ZodString;\n installed: z$1.ZodBoolean;\n compatible: z$1.ZodBoolean;\n incompatibleReason: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype PluginCatalogSearchResult$1 = z$1.infer;\n\ndeclare const systemExecutionOptionsResponseSchema: z$1.ZodObject<{\n providers: z$1.ZodArray;\n capabilities: z$1.ZodObject<{\n supportsArchive: z$1.ZodBoolean;\n supportsRename: z$1.ZodBoolean;\n supportsServiceTier: z$1.ZodBoolean;\n supportsUserQuestion: z$1.ZodBoolean;\n supportsFork: z$1.ZodBoolean;\n supportedPermissionModes: z$1.ZodArray>;\n }, z$1.core.$strip>;\n composerActions: z$1.ZodArray;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plan\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"goal\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>], \"kind\">>;\n available: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n models: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n selectedOnlyModels: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n modelLoadError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype SystemExecutionOptionsResponse = z$1.infer;\ndeclare const systemExecutionOptionsQuerySchema: z$1.ZodObject<{\n providerId: z$1.ZodOptional;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SystemExecutionOptionsQuery = z$1.infer;\n/** Omission preserves the existing behavior of reading the primary machine. */\ndeclare const systemUsageLimitsQuerySchema: z$1.ZodObject<{\n hostId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SystemUsageLimitsQuery = z$1.infer;\ndeclare const systemVoiceTranscriptionResponseSchema: z$1.ZodObject<{\n text: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemVoiceTranscriptionResponse = z$1.infer;\ndeclare const systemConfigResponseSchema: z$1.ZodObject<{\n generalSettings: z$1.ZodObject<{\n caffeinate: z$1.ZodBoolean;\n showKeyboardHints: z$1.ZodBoolean;\n showUnhandledProviderEvents: z$1.ZodBoolean;\n codexMemoryEnabled: z$1.ZodBoolean;\n claudeCodeMemoryEnabled: z$1.ZodBoolean;\n codexSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeWorkflowsDisabled: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n keybindings: z$1.ZodArray;\n desktopOnly: z$1.ZodBoolean;\n shortcut: z$1.ZodObject<{\n key: z$1.ZodString;\n mod: z$1.ZodBoolean;\n meta: z$1.ZodBoolean;\n control: z$1.ZodBoolean;\n alt: z$1.ZodBoolean;\n shift: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n when: z$1.ZodObject<{\n all: z$1.ZodArray>;\n none: z$1.ZodArray>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>>;\n defaultKeybindings: z$1.ZodArray;\n desktopOnly: z$1.ZodBoolean;\n shortcut: z$1.ZodObject<{\n key: z$1.ZodString;\n mod: z$1.ZodBoolean;\n meta: z$1.ZodBoolean;\n control: z$1.ZodBoolean;\n alt: z$1.ZodBoolean;\n shift: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n when: z$1.ZodObject<{\n all: z$1.ZodArray>;\n none: z$1.ZodArray>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>>;\n keybindingOverrides: z$1.ZodArray;\n shortcut: z$1.ZodNullable>;\n }, z$1.core.$strict>>;\n experiments: z$1.ZodObject<{\n claudeCodeMockCliTraffic: z$1.ZodBoolean;\n plugins: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n appearance: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n }, z$1.core.$strip>;\n customThemes: z$1.ZodArray;\n pluginThemes: z$1.ZodArray;\n }, z$1.core.$strip>>;\n featureFlags: z$1.ZodObject<{\n placeholder: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n hostDaemonPort: z$1.ZodNullable;\n primaryHostId: z$1.ZodNullable;\n primaryHostPlatform: z$1.ZodNullable>;\n voiceTranscriptionEnabled: z$1.ZodBoolean;\n dataDir: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemConfigResponse = z$1.infer;\ndeclare const systemAttentionResponseSchema: z$1.ZodObject<{\n hasAttention: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype SystemAttentionResponse = z$1.infer;\n/**\n * Theme catalog: the on-disk custom-theme directory plus the discovered custom\n * themes and the active palette. Drives `bb theme list` / `bb theme dir`.\n */\ndeclare const themeCatalogResponseSchema: z$1.ZodObject<{\n dir: z$1.ZodString;\n custom: z$1.ZodArray;\n plugins: z$1.ZodArray;\n }, z$1.core.$strip>>;\n active: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>;\ntype ThemeCatalogResponse = z$1.infer;\ndeclare const systemVersionResponseSchema: z$1.ZodObject<{\n currentVersion: z$1.ZodString;\n latestVersion: z$1.ZodNullable;\n source: z$1.ZodLiteral<\"npm\">;\n updateAvailable: z$1.ZodBoolean;\n isDevelopment: z$1.ZodBoolean;\n upgradeCommand: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemVersionResponse = z$1.infer;\ndeclare const systemConfigReloadResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n}, z$1.core.$strip>;\ntype SystemConfigReloadResponse = z$1.infer;\n\ndeclare const terminalSessionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodNullable;\n environmentId: z$1.ZodNullable;\n hostId: z$1.ZodString;\n title: z$1.ZodString;\n initialCwd: z$1.ZodString;\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n status: z$1.ZodEnum<{\n starting: \"starting\";\n disconnected: \"disconnected\";\n running: \"running\";\n exited: \"exited\";\n }>;\n exitCode: z$1.ZodNullable;\n closeReason: z$1.ZodNullable>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n lastUserInputAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TerminalSession = z$1.infer;\ndeclare const terminalListResponseSchema: z$1.ZodObject<{\n sessions: z$1.ZodArray;\n environmentId: z$1.ZodNullable;\n hostId: z$1.ZodString;\n title: z$1.ZodString;\n initialCwd: z$1.ZodString;\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n status: z$1.ZodEnum<{\n starting: \"starting\";\n disconnected: \"disconnected\";\n running: \"running\";\n exited: \"exited\";\n }>;\n exitCode: z$1.ZodNullable;\n closeReason: z$1.ZodNullable>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n lastUserInputAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype TerminalListResponse = z$1.infer;\ndeclare const createTerminalRequestSchema: z$1.ZodObject<{\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n start: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"command\">;\n command: z$1.ZodString;\n }, z$1.core.$strict>], \"mode\">>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"environment\">;\n environmentId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"host_path\">;\n hostId: z$1.ZodString;\n cwd: z$1.ZodNullable;\n }, z$1.core.$strict>], \"kind\">;\n title: z$1.ZodOptional;\n}, z$1.core.$strict>;\ntype CreateTerminalRequest = z$1.infer;\ndeclare const updateTerminalRequestSchema: z$1.ZodObject<{\n title: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateTerminalRequest = z$1.infer;\ndeclare const terminalInputRequestSchema: z$1.ZodObject<{\n dataBase64: z$1.ZodString;\n}, z$1.core.$strict>;\ntype TerminalInputRequest = z$1.infer;\ndeclare const terminalResizeRequestSchema: z$1.ZodObject<{\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype TerminalResizeRequest = z$1.infer;\ndeclare const terminalOutputQuerySchema: z$1.ZodObject<{\n sinceSeq: z$1.ZodOptional>;\n tailBytes: z$1.ZodOptional>;\n limitChunks: z$1.ZodOptional>;\n}, z$1.core.$strict>;\ntype TerminalOutputQuery = z$1.infer;\ndeclare const terminalOutputResponseSchema: z$1.ZodObject<{\n chunks: z$1.ZodArray>;\n nextSeq: z$1.ZodNumber;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strict>;\ntype TerminalOutputResponse = z$1.infer;\n\ndeclare const timelineRowStatusSchema: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n}>;\ntype TimelineRowStatus = z$1.infer;\ndeclare const timelineRowBaseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype TimelineRowBase = z$1.infer;\ndeclare const timelineConversationRowSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"conversation\">;\n text: z$1.ZodString;\n attachments: z$1.ZodNullable;\n localImagePaths: z$1.ZodArray;\n localFilePaths: z$1.ZodArray;\n }, z$1.core.$strip>>;\n role: z$1.ZodLiteral<\"user\">;\n initiator: z$1.ZodEnum<{\n user: \"user\";\n agent: \"agent\";\n system: \"system\";\n }>;\n senderThreadId: z$1.ZodNullable;\n systemMessageKind: z$1.ZodEnum<{\n \"ownership-assigned\": \"ownership-assigned\";\n \"ownership-removed\": \"ownership-removed\";\n \"child-needs-attention\": \"child-needs-attention\";\n \"child-completed\": \"child-completed\";\n \"child-failed\": \"child-failed\";\n \"child-interrupted\": \"child-interrupted\";\n \"child-outcome-batch\": \"child-outcome-batch\";\n unlabeled: \"unlabeled\";\n }>;\n systemMessageSubject: z$1.ZodNullable;\n threadId: z$1.ZodString;\n threadName: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-batch\">;\n count: z$1.ZodNumber;\n }, z$1.core.$strip>], \"kind\">>;\n turnRequest: z$1.ZodObject<{\n kind: z$1.ZodEnum<{\n message: \"message\";\n steer: \"steer\";\n }>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n accepted: \"accepted\";\n }>;\n }, z$1.core.$strip>;\n mentions: z$1.ZodArray, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"conversation\">;\n text: z$1.ZodString;\n attachments: z$1.ZodNullable;\n localImagePaths: z$1.ZodArray;\n localFilePaths: z$1.ZodArray;\n }, z$1.core.$strip>>;\n role: z$1.ZodLiteral<\"assistant\">;\n turnRequest: z$1.ZodNull;\n}, z$1.core.$strip>], \"role\">;\ntype TimelineConversationRow = z$1.infer;\ndeclare const timelineSystemRowSchema: z$1.ZodUnion;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n status: z$1.ZodNullable>;\n systemKind: z$1.ZodEnum<{\n error: \"error\";\n debug: \"debug\";\n reconnect: \"reconnect\";\n }>;\n}, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n status: z$1.ZodNullable>;\n systemKind: z$1.ZodLiteral<\"operation\">;\n operationKind: z$1.ZodEnum<{\n generic: \"generic\";\n compaction: \"compaction\";\n \"thread-provisioning\": \"thread-provisioning\";\n \"thread-interrupted\": \"thread-interrupted\";\n \"provider-unhandled\": \"provider-unhandled\";\n warning: \"warning\";\n deprecation: \"deprecation\";\n }>;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n systemKind: z$1.ZodLiteral<\"operation\">;\n operationKind: z$1.ZodLiteral<\"parent-change\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n parentChange: z$1.ZodObject<{\n action: z$1.ZodEnum<{\n assign: \"assign\";\n release: \"release\";\n transfer: \"transfer\";\n }>;\n previousParentThreadId: z$1.ZodNullable;\n previousParentThreadTitle: z$1.ZodNullable;\n nextParentThreadId: z$1.ZodNullable;\n nextParentThreadTitle: z$1.ZodNullable;\n }, z$1.core.$strip>;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>], \"operationKind\">]>;\ntype TimelineSystemRow = z$1.infer;\ninterface TimelineWorkRowBase extends TimelineRowBase {\n kind: \"work\";\n status: TimelineRowStatus;\n}\ndeclare const timelineCommandWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"command\">;\n callId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n source: z$1.ZodNullable;\n output: z$1.ZodString;\n exitCode: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n activityIntents: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"list_files\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype TimelineCommandWorkRow = z$1.infer;\ndeclare const timelineToolWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"tool\">;\n callId: z$1.ZodString;\n toolName: z$1.ZodString;\n toolArgs: z$1.ZodNullable>>>;\n output: z$1.ZodString;\n completedAt: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n activityIntents: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"list_files\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype TimelineToolWorkRow = z$1.infer;\ndeclare const timelineFileChangeWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"file-change\">;\n callId: z$1.ZodString;\n change: z$1.ZodObject<{\n path: z$1.ZodString;\n kind: z$1.ZodNullable;\n movePath: z$1.ZodNullable;\n diff: z$1.ZodNullable;\n diffStats: z$1.ZodObject<{\n added: z$1.ZodNumber;\n removed: z$1.ZodNumber;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>;\n stdout: z$1.ZodNullable;\n stderr: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n}, z$1.core.$strip>;\ntype TimelineFileChangeWorkRow = z$1.infer;\ndeclare const timelineWebSearchWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"web-search\">;\n callId: z$1.ZodString;\n queries: z$1.ZodArray;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWebSearchWorkRow = z$1.infer;\ndeclare const timelineWebFetchWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"web-fetch\">;\n callId: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWebFetchWorkRow = z$1.infer;\ndeclare const timelineImageViewWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"image-view\">;\n callId: z$1.ZodString;\n path: z$1.ZodString;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineImageViewWorkRow = z$1.infer;\ndeclare const timelineApprovalWorkRowSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"approval\">;\n interactionId: z$1.ZodString;\n target: z$1.ZodObject<{\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n }, z$1.core.$strip>;\n approvalKind: z$1.ZodLiteral<\"file-edit\">;\n lifecycle: z$1.ZodEnum<{\n denied: \"denied\";\n waiting: \"waiting\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"approval\">;\n interactionId: z$1.ZodString;\n target: z$1.ZodObject<{\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n }, z$1.core.$strip>;\n approvalKind: z$1.ZodLiteral<\"permission-grant\">;\n lifecycle: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n denied: \"denied\";\n resolving: \"resolving\";\n granted: \"granted\";\n }>;\n grantScope: z$1.ZodNullable>;\n statusReason: z$1.ZodNullable;\n}, z$1.core.$strip>], \"approvalKind\">;\ntype TimelineApprovalWorkRow = z$1.infer;\ndeclare const timelineQuestionWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"question\">;\n interactionId: z$1.ZodString;\n lifecycle: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n answered: \"answered\";\n }>;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n answers: z$1.ZodNullable;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n statusReason: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineQuestionWorkRow = z$1.infer;\ninterface TimelineDelegationWorkRow extends TimelineWorkRowBase {\n workKind: \"delegation\";\n callId: string;\n toolName: string;\n subagentType: string | null;\n description: string | null;\n output: string;\n completedAt: number | null;\n childRows: TimelineRow[];\n}\n/**\n * A provider background task — a dynamic workflow (Claude Code Workflow tool)\n * or a backgrounded shell command (Bash run_in_background), discriminated by\n * `taskType`. The row outlives its spawning turn: progress and terminal state\n * arrive via thread-scoped events folded into this single row. `workflow` is\n * the merged phase/agent tree, present only for workflows; null for shell\n * commands and for workflows the provider reported no progress records for\n * (degraded rendering falls back to description + summary).\n */\ndeclare const timelineWorkflowWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWorkflowWorkRow = z$1.infer;\ntype TimelineWorkRow = TimelineCommandWorkRow | TimelineToolWorkRow | TimelineFileChangeWorkRow | TimelineWebSearchWorkRow | TimelineWebFetchWorkRow | TimelineImageViewWorkRow | TimelineApprovalWorkRow | TimelineQuestionWorkRow | TimelineDelegationWorkRow | TimelineWorkflowWorkRow;\ninterface TimelineTurnRow extends TimelineRowBase {\n kind: \"turn\";\n turnId: string;\n status: TimelineRowStatus;\n summaryCount: number;\n completedAt: number | null;\n children: TimelineRow[] | null;\n}\ntype TimelineSourceRow = TimelineConversationRow | TimelineWorkRow | TimelineSystemRow;\ntype TimelineRow = TimelineSourceRow | TimelineTurnRow;\n\ndeclare const createThreadRequestSchema: z$1.ZodObject<{\n projectId: z$1.ZodString;\n providerId: z$1.ZodOptional;\n origin: z$1.ZodEnum<{\n plugin: \"plugin\";\n app: \"app\";\n cli: \"cli\";\n sdk: \"sdk\";\n }>;\n originPluginId: z$1.ZodOptional;\n visibility: z$1.ZodOptional>;\n title: z$1.ZodOptional;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n model: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n environment: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reuse\">;\n environmentId: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host\">;\n hostId: z$1.ZodOptional;\n workspace: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unmanaged\">;\n path: z$1.ZodNullable;\n branch: z$1.ZodOptional;\n name: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new\">;\n baseBranch: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"managed-worktree\">;\n baseBranch: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"named\">;\n name: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"default\">;\n }, z$1.core.$strip>], \"kind\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"personal\">;\n }, z$1.core.$strip>], \"type\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project-default\">;\n }, z$1.core.$strip>], \"type\">;\n parentThreadId: z$1.ZodOptional;\n sectionId: z$1.ZodOptional>;\n sourceThreadId: z$1.ZodOptional;\n sourceSeqEnd: z$1.ZodOptional;\n startedOnBehalfOf: z$1.ZodDefault;\n senderThreadId: z$1.ZodString;\n }, z$1.core.$strip>>>;\n originKind: z$1.ZodDefault>>;\n childOrigin: z$1.ZodDefault>>;\n}, z$1.core.$strip>;\ntype CreateThreadRequest = z$1.infer;\ndeclare const sendMessageRequestSchema: z$1.ZodObject<{\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n mode: z$1.ZodEnum<{\n steer: \"steer\";\n start: \"start\";\n auto: \"auto\";\n \"queue-if-active\": \"queue-if-active\";\n \"steer-if-active\": \"steer-if-active\";\n }>;\n senderThreadId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SendMessageRequest = z$1.infer;\ndeclare const createQueuedMessageRequestSchema: z$1.ZodObject<{\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n senderThreadId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype CreateQueuedMessageRequest = z$1.infer;\ndeclare const updateQueuedMessageRequestSchema: z$1.ZodObject<{\n expectedUpdatedAt: z$1.ZodNumber;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype UpdateQueuedMessageRequest = z$1.infer;\ndeclare const sendQueuedMessageRequestSchema: z$1.ZodObject<{\n mode: z$1.ZodEnum<{\n steer: \"steer\";\n auto: \"auto\";\n }>;\n}, z$1.core.$strip>;\ntype SendQueuedMessageRequest = z$1.infer;\ndeclare const reorderQueuedMessageRequestSchema: z$1.ZodObject<{\n previousQueuedMessageId: z$1.ZodNullable;\n nextQueuedMessageId: z$1.ZodNullable;\n groupBoundaryQueuedMessageId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ReorderQueuedMessageRequest = z$1.infer;\ndeclare const setQueuedMessageGroupBoundaryRequestSchema: z$1.ZodObject<{\n expectedGroupedPrefixQueuedMessageIds: z$1.ZodArray;\n groupBoundaryQueuedMessageId: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SetQueuedMessageGroupBoundaryRequest = z$1.infer;\ndeclare const sendQueuedMessageResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n queuedMessage: z$1.ZodObject<{\n id: z$1.ZodString;\n content: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>;\ntype SendQueuedMessageResponse = z$1.infer;\ndeclare const threadListResponseSchema: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n}, z$1.core.$strip>>;\ntype ThreadListResponse = z$1.infer;\ndeclare const threadSearchResponseSchema: z$1.ZodObject<{\n active: z$1.ZodObject<{\n total: z$1.ZodNumber;\n results: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>;\n matches: z$1.ZodArray;\n text: z$1.ZodString;\n highlightRanges: z$1.ZodArray>;\n sourceSeq: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>;\n archived: z$1.ZodObject<{\n total: z$1.ZodNumber;\n results: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>;\n matches: z$1.ZodArray;\n text: z$1.ZodString;\n highlightRanges: z$1.ZodArray>;\n sourceSeq: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>;\ntype ThreadSearchResponse = z$1.infer;\ndeclare const threadResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n environmentId: z$1.ZodNullable;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n canSpawnChild: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype ThreadResponse = z$1.infer;\ndeclare const threadGetQuerySchema: z$1.ZodObject<{\n include: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadGetQuery = z$1.infer;\ndeclare const threadWithIncludesResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n environmentId: z$1.ZodNullable;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n canSpawnChild: z$1.ZodBoolean;\n environment: z$1.ZodOptional;\n projectId: z$1.ZodString;\n hostId: z$1.ZodString;\n path: z$1.ZodNullable;\n managed: z$1.ZodBoolean;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n branchName: z$1.ZodNullable;\n baseBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n mergeBaseBranch: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n ready: \"ready\";\n retiring: \"retiring\";\n destroying: \"destroying\";\n destroyed: \"destroyed\";\n }>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>>>;\n host: z$1.ZodOptional;\n status: z$1.ZodEnum<{\n disconnected: \"disconnected\";\n connected: \"connected\";\n }>;\n lastSeenAt: z$1.ZodNullable;\n lastRejectedProtocolVersion: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>>>;\n}, z$1.core.$strip>;\ntype ThreadWithIncludesResponse = z$1.infer;\ndeclare const threadPendingInteractionsResponseSchema: z$1.ZodArray;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n origin: z$1.ZodOptional;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n }, z$1.core.$strip>>;\n payload: z$1.ZodUnion;\n subject: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n itemId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n actions: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"listFiles\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"file_change\">;\n itemId: z$1.ZodString;\n writeScope: z$1.ZodNullable;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>], \"kind\">;\n reason: z$1.ZodNullable;\n availableDecisions: z$1.ZodArray>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>;\n resolution: z$1.ZodNullable;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodNullable;\n origin: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n rendererId: z$1.ZodString;\n }, z$1.core.$strip>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n title: z$1.ZodString;\n data: z$1.ZodType>;\n }, z$1.core.$strip>;\n resolution: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>]>>;\ntype ThreadPendingInteractionsResponse = z$1.infer;\ndeclare const threadQueuedMessageListResponseSchema: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>>;\ntype ThreadQueuedMessageListResponse = z$1.infer;\ndeclare const threadChildSummaryResponseSchema: z$1.ZodObject<{\n nonDeletedChildCount: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadChildSummaryResponse = z$1.infer;\ndeclare const deleteThreadRequestSchema: z$1.ZodObject<{\n childThreadsConfirmed: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype DeleteThreadRequest = z$1.infer;\ndeclare const updateThreadRequestSchema: z$1.ZodObject<{\n title: z$1.ZodOptional>;\n sectionId: z$1.ZodOptional>;\n parentThreadId: z$1.ZodOptional>;\n model: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype UpdateThreadRequest = z$1.infer;\ndeclare const reorderPinnedThreadRequestSchema: z$1.ZodObject<{\n previousThreadId: z$1.ZodNullable;\n nextThreadId: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ReorderPinnedThreadRequest = z$1.infer;\n/**\n * Requested placement for a thread opened in the app's split layout. Edge\n * placements add panes through the eighth pane; at the cap they replace the\n * focused pane. `replace` always replaces the focused pane.\n */\ndeclare const threadOpenSplitSchema: z$1.ZodEnum<{\n right: \"right\";\n down: \"down\";\n left: \"left\";\n top: \"top\";\n replace: \"replace\";\n}>;\ntype ThreadOpenSplit = z$1.infer;\n/** Optional secondary-panel file to open with a thread. */\ndeclare const threadOpenFileSchema: z$1.ZodObject<{\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n path: z$1.ZodString;\n lineNumber: z$1.ZodNullable;\n}, z$1.core.$strict>;\ntype ThreadOpenFile = z$1.infer;\n/** Response for POST /threads/:id/open: how many connected clients received it. */\ndeclare const threadOpenResponseSchema: z$1.ZodObject<{\n delivered: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadOpenResponse = z$1.infer;\n/** Presentation action for one thread pane in each connected app window. */\ndeclare const threadPaneActionSchema: z$1.ZodEnum<{\n maximize: \"maximize\";\n restore: \"restore\";\n toggle: \"toggle\";\n}>;\ntype ThreadPaneAction = z$1.infer;\n/** Number of connected app clients that received the pane action. */\ndeclare const threadPaneActionResponseSchema: z$1.ZodObject<{\n delivered: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadPaneActionResponse = z$1.infer;\ndeclare const threadArchiveAllResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n archivedThreadIds: z$1.ZodArray;\n}, z$1.core.$strip>;\ntype ThreadArchiveAllResponse = z$1.infer;\ndeclare const threadListQuerySchema: z$1.ZodObject<{\n projectId: z$1.ZodOptional;\n parentThreadId: z$1.ZodOptional;\n sourceThreadId: z$1.ZodOptional;\n archived: z$1.ZodOptional>;\n sectionId: z$1.ZodOptional;\n unsectioned: z$1.ZodOptional>;\n hasParent: z$1.ZodOptional>;\n originKind: z$1.ZodOptional>;\n excludeSideChats: z$1.ZodOptional>;\n childOrigin: z$1.ZodOptional>;\n limit: z$1.ZodOptional;\n offset: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadListQuery = z$1.infer;\ndeclare const threadSearchQuerySchema: z$1.ZodObject<{\n query: z$1.ZodString;\n limitPerGroup: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadSearchQuery = z$1.infer;\ndeclare const threadTimelineQuerySchema: z$1.ZodObject<{\n includeNestedRows: z$1.ZodOptional>;\n segmentLimit: z$1.ZodOptional;\n beforeAnchorSeq: z$1.ZodOptional;\n beforeAnchorId: z$1.ZodOptional;\n summaryOnly: z$1.ZodOptional>;\n afterSequence: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadTimelineQuery = z$1.infer;\ndeclare const timelineTurnSummaryDetailsQuerySchema: z$1.ZodObject<{\n turnId: z$1.ZodString;\n sourceSeqStart: z$1.ZodString;\n sourceSeqEnd: z$1.ZodString;\n}, z$1.core.$strip>;\ntype TimelineTurnSummaryDetailsQuery = z$1.infer;\ndeclare const threadStorageFilesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadStorageFilesQuery = z$1.infer;\ndeclare const threadStoragePathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n}, z$1.core.$strip>;\ntype ThreadStoragePathsQuery = z$1.infer;\ndeclare const timelineTurnSummaryDetailsResponseSchema: z$1.ZodObject<{\n rows: z$1.ZodArray>>;\n}, z$1.core.$strip>;\ntype TimelineTurnSummaryDetailsResponse = z$1.infer;\ndeclare const threadTimelineResponseSchema: z$1.ZodObject<{\n rows: z$1.ZodArray>>;\n activePromptMode: z$1.ZodNullable;\n providerId: z$1.ZodEnum<{\n codex: \"codex\";\n \"claude-code\": \"claude-code\";\n }>;\n prompt: z$1.ZodString;\n }, z$1.core.$strict>>;\n activeThinking: z$1.ZodNullable>;\n activeWorkflow: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n activeBackgroundCommands: z$1.ZodArray;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n pendingTodos: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n goal: z$1.ZodNullable;\n tokenBudget: z$1.ZodNullable;\n tokensUsed: z$1.ZodNumber;\n timeUsedSeconds: z$1.ZodNumber;\n }, z$1.core.$strip>>;\n modelFallback: z$1.ZodNullable;\n message: z$1.ZodString;\n }, z$1.core.$strip>>;\n contextWindowUsage: z$1.ZodOptional>;\n timelinePage: z$1.ZodObject<{\n kind: z$1.ZodEnum<{\n latest: \"latest\";\n older: \"older\";\n }>;\n segmentLimit: z$1.ZodNumber;\n returnedSegmentCount: z$1.ZodNumber;\n hasOlderRows: z$1.ZodBoolean;\n olderCursor: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n maxSeq: z$1.ZodNumber;\n delta: z$1.ZodOptional>>;\n rowOrder: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ThreadTimelineResponse = z$1.infer;\ndeclare const threadConversationOutlineResponseSchema: z$1.ZodObject<{\n items: z$1.ZodArray;\n preview: z$1.ZodString;\n attachmentSummary: z$1.ZodNullable>;\n }, z$1.core.$strict>>;\n maxSeq: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadConversationOutlineResponse = z$1.infer;\ndeclare const threadStorageFileListResponseSchema: z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n storageRootPath: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ThreadStorageFileListResponse = z$1.infer;\ndeclare const threadStoragePathListResponseSchema: z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n storageRootPath: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ThreadStoragePathListResponse = z$1.infer;\n\ndeclare const threadTabsResponseSchema: z$1.ZodObject<{\n revision: z$1.ZodNumber;\n tabs: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"git-diff\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n actionId: z$1.ZodString;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"plugin-panel\">;\n paramsJson: z$1.ZodNullable;\n pluginId: z$1.ZodString;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n projectId: z$1.ZodNullable;\n source: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"working-tree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"head\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge-base\">;\n ref: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">;\n statusLabel: z$1.ZodNullable>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"host-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n isPinned: z$1.ZodBoolean;\n kind: z$1.ZodLiteral<\"thread-storage-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"browser\">;\n title: z$1.ZodNullable;\n url: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"new-tab\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"side-chat\">;\n sourceMessageText: z$1.ZodString;\n sourceSeqEnd: z$1.ZodNullable;\n threadId: z$1.ZodNullable;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"terminal\">;\n terminalId: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n}, z$1.core.$strict>;\ntype ThreadTabsResponse = z$1.infer;\ndeclare const updateThreadTabsRequestSchema: z$1.ZodObject<{\n expectedRevision: z$1.ZodNumber;\n tabs: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"git-diff\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n actionId: z$1.ZodString;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"plugin-panel\">;\n paramsJson: z$1.ZodNullable;\n pluginId: z$1.ZodString;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n projectId: z$1.ZodNullable;\n source: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"working-tree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"head\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge-base\">;\n ref: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">;\n statusLabel: z$1.ZodNullable>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"host-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n isPinned: z$1.ZodBoolean;\n kind: z$1.ZodLiteral<\"thread-storage-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"browser\">;\n title: z$1.ZodNullable;\n url: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"new-tab\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"side-chat\">;\n sourceMessageText: z$1.ZodString;\n sourceSeqEnd: z$1.ZodNullable;\n threadId: z$1.ZodNullable;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"terminal\">;\n terminalId: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n}, z$1.core.$strict>;\ntype UpdateThreadTabsRequest = z$1.infer;\n\ninterface EnvironmentActionArgs {\n environmentId: string;\n}\ninterface EnvironmentGetArgs extends EnvironmentActionArgs {\n signal?: AbortSignal;\n}\ntype EnvironmentMergeBaseBranchUpdateValue = Exclude;\ntype EnvironmentNameUpdateValue = Exclude;\ninterface EnvironmentMergeBaseBranchUpdate {\n mergeBaseBranch: EnvironmentMergeBaseBranchUpdateValue;\n name?: EnvironmentNameUpdateValue;\n}\ninterface EnvironmentNameUpdate {\n mergeBaseBranch?: EnvironmentMergeBaseBranchUpdateValue;\n name: EnvironmentNameUpdateValue;\n}\ntype EnvironmentUpdateFields = EnvironmentMergeBaseBranchUpdate | EnvironmentNameUpdate;\ntype EnvironmentUpdateArgs = EnvironmentUpdateFields & {\n environmentId: string;\n};\ninterface EnvironmentStatusArgs extends EnvironmentStatusQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ntype EnvironmentDiffArgs = EnvironmentDiffQuery & {\n environmentId: string;\n signal?: AbortSignal;\n};\ntype EnvironmentDiffFileArgs = EnvironmentDiffFileQuery & {\n environmentId: string;\n signal?: AbortSignal;\n};\ninterface EnvironmentDiffBranchesArgs extends EnvironmentDiffBranchesQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ninterface EnvironmentCommitArgs {\n environmentId: string;\n}\ninterface EnvironmentSquashMergeArgs {\n environmentId: string;\n mergeBaseBranch: string;\n}\ninterface EnvironmentPullRequestMergeArgs {\n environmentId: string;\n method: PullRequestMergeMethod;\n}\ntype EnvironmentDiffPatchArgs = EnvironmentDiffPatchRequest & {\n environmentId: string;\n signal?: AbortSignal;\n};\ninterface EnvironmentPathsArgs extends EnvironmentPathsQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ntype EnvironmentArchiveThreadsResult = EnvironmentArchiveThreadsResponse;\ntype EnvironmentCommitResult = CommitActionResponse;\ntype EnvironmentDiffResult = EnvironmentDiffResponse;\ntype EnvironmentDiffBranchesResult = EnvironmentDiffBranchesResponse;\ntype EnvironmentDiffFileResult = EnvironmentDiffFileResponse;\ntype EnvironmentDiffFilesResult = EnvironmentDiffFilesResponse;\ntype EnvironmentDiffPatchResult = EnvironmentDiffPatchResponse;\ntype EnvironmentGetResult = Environment;\ntype EnvironmentMarkPullRequestDraftResult = PullRequestDraftActionResponse;\ntype EnvironmentMarkPullRequestReadyResult = PullRequestReadyActionResponse;\ntype EnvironmentMergePullRequestResult = PullRequestMergeActionResponse;\ntype EnvironmentPathsResult = WorkspacePathListResponse;\ntype EnvironmentPullRequestResult = EnvironmentPullRequestResponse;\ntype EnvironmentSquashMergeResult = SquashMergeActionResponse;\ntype EnvironmentStatusResult = EnvironmentStatusResponse;\ntype EnvironmentUpdateResult = Environment;\ninterface EnvironmentsArea {\n archiveThreads(args: EnvironmentActionArgs): Promise;\n commit(args: EnvironmentCommitArgs): Promise;\n diff(args: EnvironmentDiffArgs): Promise;\n diffBranches(args: EnvironmentDiffBranchesArgs): Promise;\n diffFile(args: EnvironmentDiffFileArgs): Promise;\n diffFiles(args: EnvironmentDiffArgs): Promise;\n diffPatch(args: EnvironmentDiffPatchArgs): Promise;\n get(args: EnvironmentGetArgs): Promise;\n pullRequest(args: EnvironmentGetArgs): Promise;\n markPullRequestDraft(args: EnvironmentActionArgs): Promise;\n markPullRequestReady(args: EnvironmentActionArgs): Promise;\n mergePullRequest(args: EnvironmentPullRequestMergeArgs): Promise;\n paths(args: EnvironmentPathsArgs): Promise;\n squashMerge(args: EnvironmentSquashMergeArgs): Promise;\n status(args: EnvironmentStatusArgs): Promise;\n update(args: EnvironmentUpdateArgs): Promise;\n}\n\n/**\n * Host file primitives. `hostId` may be omitted to target the server's\n * primary (local) host. `rootPath`, when set, confines the target beneath\n * that absolute root on the host (symlink-safe).\n */\ninterface FileReadArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n signal?: AbortSignal;\n}\ninterface FileWriteArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n content: string;\n /** Defaults to \"utf8\". */\n contentEncoding?: \"utf8\" | \"base64\";\n /** Defaults to false. */\n createParents?: boolean;\n /**\n * Optimistic-concurrency guard: omitted → unconditional write; a hash →\n * write only when the current content hashes to it (use `read().sha256`);\n * null → create-only. A failed guard resolves to the `conflict` outcome.\n */\n expectedSha256?: string | null;\n /** POSIX permission bits used when creating a file (for example 0o600). */\n mode?: number;\n}\ninterface FileListArgs {\n hostId?: string;\n path: string;\n query?: string;\n limit?: number;\n signal?: AbortSignal;\n}\ninterface PathListArgs extends FileListArgs {\n includeFiles: boolean;\n includeDirectories: boolean;\n}\ninterface FileMkdirArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n recursive?: boolean;\n}\ninterface FileMoveArgs {\n hostId?: string;\n sourcePath: string;\n destinationPath: string;\n rootPath?: string;\n}\ninterface FileRemoveArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n recursive?: boolean;\n}\ninterface FilePreviewArgs {\n hostId?: string;\n rootPath: string;\n signal?: AbortSignal;\n ttlMs?: number;\n}\ntype FileReadResult = HostFileReadResponse;\ntype FileWriteResult = HostFileWriteResponse;\ntype FileListResult = HostFileListResponse;\ntype PathListResult = HostPathListResponse;\ntype FileMkdirResult = HostMkdirResponse;\ntype FileMoveResult = HostMovePathResponse;\ntype FileRemoveResult = HostRemovePathResponse;\ntype FilePreviewResult = CreateFilePreviewResponse;\ninterface FilesArea {\n read(args: FileReadArgs): Promise;\n write(args: FileWriteArgs): Promise;\n list(args: FileListArgs): Promise;\n listPaths(args: PathListArgs): Promise;\n mkdir(args: FileMkdirArgs): Promise;\n move(args: FileMoveArgs): Promise;\n remove(args: FileRemoveArgs): Promise;\n createPreview(args: FilePreviewArgs): Promise;\n}\n\ninterface GuideRenderArgs {\n chapter?: string;\n}\ninterface GuideRenderResult {\n chapter?: string;\n content: string;\n}\ninterface GuideArea {\n render(args?: GuideRenderArgs): GuideRenderResult;\n}\n\ninterface HostGetArgs {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostDeleteArgs {\n hostId: string;\n}\ninterface HostUpdateArgs extends UpdateHostRequest {\n hostId: string;\n}\ninterface HostDirectoryArgs extends HostDirectoryQuery {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostCloneDefaultPathArgs extends HostCloneDefaultPathQuery {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostPathsExistArgs extends HostPathsExistRequest {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostPickFolderArgs extends HostPickFolderRequest {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostProviderCliInstallArgs extends HostProviderCliInstallRequest {\n hostId: string;\n}\ninterface HostListArgs {\n signal?: AbortSignal;\n}\ntype HostCreateJoinCodeResult = CreateHostJoinCodeResponse;\ntype HostDeleteResult = {\n ok: true;\n};\ntype HostDirectoryResult = HostDirectoryListing;\ntype HostGetResult = Host;\ntype HostCloneDefaultPathResult = HostCloneDefaultPathResponse;\ntype HostProviderCliInstallResult = HostProviderCliInstallEvent[];\ntype HostListResult = Host[];\ntype HostPathsExistResult = HostPathsExistResponse;\ntype HostPickFolderResult = HostPickFolderResponse;\ntype HostProviderCliStatusResult = HostProviderCliStatusResponse;\ntype HostUpdateResult = Host;\ninterface HostsArea {\n createJoinCode(): Promise;\n delete(args: HostDeleteArgs): Promise;\n directory(args: HostDirectoryArgs): Promise;\n get(args: HostGetArgs): Promise;\n cloneDefaultPath(args: HostCloneDefaultPathArgs): Promise;\n installProviderCli(args: HostProviderCliInstallArgs): Promise;\n list(args?: HostListArgs): Promise;\n pathsExist(args: HostPathsExistArgs): Promise;\n pickFolder(args: HostPickFolderArgs): Promise;\n providerCliStatus(args: HostGetArgs): Promise;\n update(args: HostUpdateArgs): Promise;\n}\n\ninterface ProjectListArgs {\n include?: ProjectListQuery[\"include\"];\n /** Include the singleton personal project. Defaults to false for compatibility. */\n includePersonal?: boolean;\n signal?: AbortSignal;\n}\ninterface ProjectCreateArgs extends CreateProjectRequest {\n}\ninterface ProjectGetArgs {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectUpdateArgs extends UpdateProjectRequest {\n projectId: string;\n}\ninterface ProjectDeleteArgs {\n projectId: string;\n}\ninterface ProjectReorderArgs extends ReorderProjectRequest {\n projectId: string;\n}\ninterface ProjectPromptHistoryArgs extends PromptHistoryQuery {\n projectId: string;\n signal?: AbortSignal;\n}\n/** Select one project workspace source, or omit both for the primary host. */\ntype ProjectWorkspaceRoutingArgs = {\n environmentId: string;\n hostId?: never;\n} | {\n environmentId?: never;\n hostId: string;\n} | {\n environmentId?: never;\n hostId?: never;\n};\ntype ProjectFilesArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectPathsArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectCommandsArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectFileContentArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ninterface ProjectBranchesArgs extends ProjectBranchesQuery {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectDefaultExecutionOptionsArgs {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectAttachmentFileLike {\n arrayBuffer(): Promise;\n readonly name: string;\n readonly type?: string;\n}\ninterface ProjectAttachmentUploadArgsBase {\n /** MIME override. Omit to use the File/Blob type, when available. */\n mimeType?: string;\n projectId: string;\n}\n/**\n * Upload bytes owned by this SDK client. A bare Blob/byte buffer needs an\n * explicit filename; File-like values can supply their own name.\n */\ntype ProjectAttachmentUploadArgs = ProjectAttachmentUploadArgsBase & ({\n clientFile: ProjectAttachmentFileLike;\n filename?: string;\n} | {\n clientFile: ArrayBuffer | Blob | Uint8Array;\n filename: string;\n});\ninterface ProjectAttachmentReadArgs {\n path: string;\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectAttachmentCopyArgs extends CopyProjectAttachmentsRequest {\n projectId: string;\n}\ntype ProjectSourceAddArgs = CreateProjectSourceRequest & {\n projectId: string;\n};\ninterface ProjectSourceUpdateArgs extends UpdateProjectSourceRequest {\n projectId: string;\n sourceId: string;\n}\ninterface ProjectSourceDeleteArgs {\n projectId: string;\n sourceId: string;\n}\ntype ProjectBranchesResult = ProjectBranchesResponse;\ninterface ProjectAttachmentReadResult {\n bytes: Uint8Array;\n mimeType: string;\n sizeBytes: number;\n}\ntype ProjectAttachmentUploadResult = UploadedPromptAttachment;\ntype ProjectCommandsResult = CommandListResponse;\ntype ProjectCreateResult = ProjectResponse;\ntype ProjectDefaultExecutionOptionsResult = ProjectExecutionDefaults | null;\ntype ProjectDeleteResult = {\n ok: true;\n};\ninterface ProjectFileContentResult {\n /** UTF-8 text or base64, as selected by `contentEncoding`. */\n content: string;\n contentEncoding: \"utf8\" | \"base64\";\n mimeType: string;\n sizeBytes: number;\n}\ntype ProjectFilesResult = WorkspaceFileListResponse;\ntype ProjectGetResult = ProjectResponse;\ntype ProjectListResult = ProjectResponse[] | ProjectWithThreadsResponse[];\ntype ProjectPathsResult = WorkspacePathListResponse;\ntype ProjectPromptHistoryResult = PromptHistoryResponse;\ntype ProjectReorderResult = ProjectResponse[];\ntype ProjectSourceAddResult = ProjectSource;\ntype ProjectSourceDeleteResult = {\n ok: true;\n};\ntype ProjectSourceUpdateResult = ProjectSource;\ntype ProjectUpdateResult = ProjectResponse;\ninterface ProjectSourcesArea {\n add(args: ProjectSourceAddArgs): Promise;\n delete(args: ProjectSourceDeleteArgs): Promise;\n update(args: ProjectSourceUpdateArgs): Promise;\n}\ninterface ProjectAttachmentsArea {\n copy(args: ProjectAttachmentCopyArgs): Promise;\n read(args: ProjectAttachmentReadArgs): Promise;\n upload(args: ProjectAttachmentUploadArgs): Promise;\n}\ninterface ProjectsArea {\n attachments: ProjectAttachmentsArea;\n branches(args: ProjectBranchesArgs): Promise;\n commands(args: ProjectCommandsArgs): Promise;\n create(args: ProjectCreateArgs): Promise;\n defaultExecutionOptions(args: ProjectDefaultExecutionOptionsArgs): Promise;\n delete(args: ProjectDeleteArgs): Promise;\n fileContent(args: ProjectFileContentArgs): Promise;\n files(args: ProjectFilesArgs): Promise;\n get(args: ProjectGetArgs): Promise;\n list(args?: ProjectListArgs): Promise;\n paths(args: ProjectPathsArgs): Promise;\n promptHistory(args: ProjectPromptHistoryArgs): Promise;\n reorder(args: ProjectReorderArgs): Promise;\n sources: ProjectSourcesArea;\n update(args: ProjectUpdateArgs): Promise;\n}\n\n/** Select exactly one provider-discovery host source, or omit both for primary. */\ntype ProviderHostRoutingArgs = {\n environmentId: string;\n hostId?: never;\n} | {\n environmentId?: never;\n hostId: string;\n} | {\n environmentId?: never;\n hostId?: never;\n};\ntype ProviderListArgs = ProviderHostRoutingArgs & {\n signal?: AbortSignal;\n};\ntype ProviderModelsArgs = ProviderHostRoutingArgs & {\n providerId?: string;\n signal?: AbortSignal;\n};\ntype ProviderListResult = ProviderInfo[];\ntype ProviderModelsResult = SystemExecutionOptionsResponse;\ninterface ProvidersArea {\n /** List providers on the environment host, explicit host, or primary host. */\n list(args?: ProviderListArgs): Promise;\n /** List models on the environment host, explicit host, or primary host. */\n models(args?: ProviderModelsArgs): Promise;\n}\n\ninterface PluginIdArgs {\n pluginId: string;\n}\n/** Install directly from a path:, git:, npm:, or builtin: source spec. */\ninterface PluginInstallArgs {\n source: string;\n}\n/** Install an entry from BB's official catalog. */\ninterface PluginCatalogInstallArgs {\n entryId: string;\n}\ninterface PluginReloadArgs {\n pluginId?: string;\n}\ninterface PluginSettingsUpdateArgs extends PluginIdArgs {\n values: Record;\n}\ninterface PluginTokenArgs extends PluginIdArgs {\n rotate?: boolean;\n}\ninterface PluginCheckUpdatesArgs {\n pluginId?: string;\n signal?: AbortSignal;\n}\ninterface PluginRpcArgs extends PluginIdArgs {\n input?: JsonValue;\n method: string;\n outputSchema: z$1.ZodType;\n}\ninterface PluginCatalogSearchArgs {\n query: string;\n signal?: AbortSignal;\n}\ninterface PluginCatalogStatusArgs {\n signal?: AbortSignal;\n}\ninterface PluginGetSettingsArgs extends PluginIdArgs {\n signal?: AbortSignal;\n}\ninterface PluginGetSourceArgs extends PluginIdArgs {\n signal?: AbortSignal;\n}\ninterface PluginListArgs {\n signal?: AbortSignal;\n}\ninterface PluginListUpdateResultsArgs {\n signal?: AbortSignal;\n}\ntype PluginDisableResult = InstalledPlugin;\ntype PluginEnableResult = InstalledPlugin;\ntype PluginGetSettingsResult = PluginSettingsResponse;\ntype PluginInstallResult = InstalledPlugin;\ntype PluginListResult = PluginListResponse;\ntype PluginReloadResult = PluginReloadResponse;\ntype PluginRemoveResult = PluginRemoveResponse;\ntype PluginTokenResult = PluginTokenResponse;\ntype PluginUpdateSettingsResult = PluginSettingsResponse;\ntype PluginGetSourceResult = PluginSourceDetail;\ntype PluginCheckUpdatesResult = PluginUpdateCheckEntry[];\ntype PluginApplyUpdateResult = PluginApplyUpdateResult$1;\ntype PluginCatalogStatusResult = PluginCatalogStatus;\ntype PluginCatalogSearchResult = PluginCatalogSearchResult$1[];\ninterface PluginCatalogArea {\n install(args: PluginCatalogInstallArgs): Promise;\n search(args: PluginCatalogSearchArgs): Promise;\n status(args?: PluginCatalogStatusArgs): Promise;\n}\ninterface PluginsArea {\n applyUpdate(args: PluginIdArgs): Promise;\n callRpc(args: PluginRpcArgs): Promise;\n checkUpdates(args?: PluginCheckUpdatesArgs): Promise;\n catalog: PluginCatalogArea;\n disable(args: PluginIdArgs): Promise;\n enable(args: PluginIdArgs): Promise;\n getSettings(args: PluginGetSettingsArgs): Promise;\n getSource(args: PluginGetSourceArgs): Promise;\n install(args: PluginInstallArgs): Promise;\n list(args?: PluginListArgs): Promise;\n listUpdateResults(args?: PluginListUpdateResultsArgs): Promise;\n reload(args?: PluginReloadArgs): Promise;\n remove(args: PluginIdArgs): Promise;\n token(args: PluginTokenArgs): Promise;\n updateSettings(args: PluginSettingsUpdateArgs): Promise;\n}\n\ntype BbRealtimeUnsubscribe = () => void;\ntype BbRealtimeEventName = \"thread:changed\" | \"project:changed\" | \"environment:changed\" | \"host:changed\" | \"system:changed\" | \"system:config-changed\" | \"realtime:connection\";\ntype ThreadRealtimeEvent = Extract;\ntype ProjectRealtimeEvent = Extract;\ntype EnvironmentRealtimeEvent = Extract;\ntype HostRealtimeEvent = Extract;\ntype SystemRealtimeEvent = Extract;\ntype BbRealtimeConnectionState = \"connecting\" | \"connected\" | \"disconnected\";\ninterface BbRealtimeConnectionEvent {\n reconnectDelayMs: number | null;\n reconnected: boolean;\n state: BbRealtimeConnectionState;\n}\n/**\n * Entity-changed events are delivered as one shared object to every matching\n * listener; their payload types are readonly so a listener cannot mutate what\n * the next listener receives.\n */\ninterface BbRealtimeEventMap {\n \"thread:changed\": ThreadRealtimeEvent;\n \"project:changed\": ProjectRealtimeEvent;\n \"environment:changed\": EnvironmentRealtimeEvent;\n \"host:changed\": HostRealtimeEvent;\n \"system:changed\": SystemRealtimeEvent;\n \"system:config-changed\": SystemRealtimeEvent;\n \"realtime:connection\": BbRealtimeConnectionEvent;\n}\ntype BbRealtimeCallback = (event: BbRealtimeEventMap[TEventName]) => void;\ninterface ThreadRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"thread:changed\">;\n event: \"thread:changed\";\n threadId?: string;\n}\ninterface ProjectRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"project:changed\">;\n event: \"project:changed\";\n projectId?: string;\n}\ninterface EnvironmentRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"environment:changed\">;\n environmentId?: string;\n event: \"environment:changed\";\n}\ninterface HostRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"host:changed\">;\n event: \"host:changed\";\n hostId?: string;\n}\ninterface SystemRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"system:changed\">;\n event: \"system:changed\";\n}\ninterface SystemConfigRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"system:config-changed\">;\n event: \"system:config-changed\";\n}\n/**\n * Connection listeners are pure observers — they never open or hold the\n * socket. A listener registered while a socket already exists receives the\n * latest connection event as a snapshot on the next microtask, so a status\n * UI mounted after connect still learns the current state.\n */\ninterface RealtimeConnectionSubscribeArgs {\n callback: BbRealtimeCallback<\"realtime:connection\">;\n event: \"realtime:connection\";\n}\ntype BbRealtimeSubscribeArgsUnion = ThreadRealtimeSubscribeArgs | ProjectRealtimeSubscribeArgs | EnvironmentRealtimeSubscribeArgs | HostRealtimeSubscribeArgs | SystemRealtimeSubscribeArgs | SystemConfigRealtimeSubscribeArgs | RealtimeConnectionSubscribeArgs;\ntype BbRealtimeSubscribeArgs = Extract;\ninterface BbRealtime {\n subscribe(args: BbRealtimeSubscribeArgs): BbRealtimeUnsubscribe;\n}\n\ninterface StatusGetArgs {\n projectId?: string;\n signal?: AbortSignal;\n threadId?: string;\n}\ninterface StatusThreadSummary {\n environmentId: string | null;\n id: string;\n parentThreadId: string | null;\n pinnedAt: number | null;\n projectId: string;\n status: ThreadStatus;\n title: string | null;\n}\ntype StatusProject = ProjectResponse;\ntype StatusChildThreads = ThreadListResponse;\ninterface StatusResult {\n childThreads: StatusChildThreads | null;\n pendingTodos: ThreadTimelinePendingTodos | null;\n project: StatusProject | null;\n thread: StatusThreadSummary | null;\n}\ninterface StatusArea {\n get(args?: StatusGetArgs): Promise;\n}\n\ntype ThemeGetResult = AppTheme;\ntype ThemeCatalogResult = ThemeCatalogResponse;\ntype ThemeSetInput = AppThemeSelection;\ntype ThemeSetResult = AppTheme;\ninterface ThemeCatalogArgs {\n signal?: AbortSignal;\n}\ninterface ThemeGetArgs {\n signal?: AbortSignal;\n}\ninterface ThemeArea {\n /** The active app palette, resolved server-side (built-in id or custom CSS). */\n get(args?: ThemeGetArgs): Promise;\n /** The custom-theme directory plus discovered themes and the active palette. */\n catalog(args?: ThemeCatalogArgs): Promise;\n /** Set the complete app appearance selection in one request. */\n set(selection: ThemeSetInput): Promise;\n /**\n * Activate a palette by id while preserving the active favicon color. This\n * compatibility shorthand reads the active appearance before writing the\n * complete selection; prefer the object form when both values are known.\n */\n set(themeId: string): Promise;\n}\n\ninterface SystemAttentionArgs {\n signal?: AbortSignal;\n}\ninterface SystemConfigArgs {\n signal?: AbortSignal;\n}\ninterface SystemExecutionOptionsArgs extends SystemExecutionOptionsQuery {\n signal?: AbortSignal;\n}\ninterface SystemUsageLimitsArgs extends SystemUsageLimitsQuery {\n signal?: AbortSignal;\n}\ninterface SystemVersionArgs {\n force?: boolean;\n signal?: AbortSignal;\n}\ninterface SystemVoiceTranscriptionArgs {\n file: Blob;\n prompt?: string;\n signal?: AbortSignal;\n}\ntype SystemAttentionResult = SystemAttentionResponse;\ntype SystemConfigResult = SystemConfigResponse;\ntype SystemExecutionOptionsResult = SystemExecutionOptionsResponse;\ntype SystemReloadConfigResult = SystemConfigReloadResponse;\ntype SystemVoiceTranscriptionResult = SystemVoiceTranscriptionResponse;\ntype SystemUpdateExperimentsResult = Experiments;\ntype SystemUpdateGeneralSettingsResult = AppSettings;\ntype SystemUpdateKeyboardSettingsResult = AppKeybindingOverrides;\ntype SystemUsageLimitsResult = ProviderUsageResponse;\ntype SystemVersionResult = SystemVersionResponse;\ninterface SystemArea {\n attention(args?: SystemAttentionArgs): Promise;\n config(args?: SystemConfigArgs): Promise;\n executionOptions(args?: SystemExecutionOptionsArgs): Promise;\n reloadConfig(): Promise;\n transcribeVoice(args: SystemVoiceTranscriptionArgs): Promise;\n updateExperiments(args: Experiments): Promise;\n updateGeneralSettings(args: AppSettings): Promise;\n updateKeyboardSettings(args: AppKeybindingOverrides): Promise;\n usageLimits(args?: SystemUsageLimitsArgs): Promise;\n version(args?: SystemVersionArgs): Promise;\n}\n\ninterface TerminalThreadScope {\n cwd?: never;\n environmentId?: never;\n hostId?: never;\n kind: \"thread\";\n threadId: string;\n}\ninterface TerminalEnvironmentScope {\n environmentId: string;\n cwd?: never;\n hostId?: never;\n kind: \"environment\";\n threadId?: never;\n}\ninterface TerminalHostPathListScope {\n /** Optional exact initial working-directory filter on the selected host. */\n cwd?: string;\n environmentId?: never;\n hostId: string;\n kind: \"host_path\";\n threadId?: never;\n}\ninterface TerminalHostPathCreateScope {\n /** Null starts in the selected host's home directory. */\n cwd: string | null;\n environmentId?: never;\n hostId: string;\n kind: \"host_path\";\n threadId?: never;\n}\ntype TerminalListScope = TerminalThreadScope | TerminalEnvironmentScope | TerminalHostPathListScope;\ntype TerminalCreateScope = TerminalThreadScope | TerminalEnvironmentScope | TerminalHostPathCreateScope;\ninterface TerminalListArgs {\n signal?: AbortSignal;\n scope: TerminalListScope;\n}\ninterface TerminalCreateArgs {\n cols: number;\n rows: number;\n scope: TerminalCreateScope;\n start?: CreateTerminalRequest[\"start\"];\n title?: string;\n}\ninterface TerminalTargetArgs {\n terminalId: string;\n}\ninterface TerminalGetArgs extends TerminalTargetArgs {\n signal?: AbortSignal;\n}\ninterface TerminalRenameArgs extends TerminalTargetArgs {\n title: UpdateTerminalRequest[\"title\"];\n}\ninterface TerminalCloseArgs extends TerminalTargetArgs {\n mode: \"force\" | \"if-clean\";\n}\ninterface TerminalInputArgs extends TerminalTargetArgs {\n dataBase64: TerminalInputRequest[\"dataBase64\"];\n}\ninterface TerminalResizeArgs extends TerminalTargetArgs {\n cols: TerminalResizeRequest[\"cols\"];\n rows: TerminalResizeRequest[\"rows\"];\n}\ninterface TerminalOutputArgs extends TerminalTargetArgs {\n limitChunks?: TerminalOutputQuery[\"limitChunks\"];\n signal?: AbortSignal;\n sinceSeq?: TerminalOutputQuery[\"sinceSeq\"];\n tailBytes?: TerminalOutputQuery[\"tailBytes\"];\n}\ntype TerminalRestartArgs = TerminalTargetArgs;\ntype TerminalListResult = TerminalListResponse;\ntype TerminalCreateResult = TerminalSession;\ntype TerminalGetResult = TerminalSession;\ntype TerminalRenameResult = TerminalSession;\ntype TerminalCloseResult = TerminalSession;\ntype TerminalInputResult = TerminalSession;\ntype TerminalResizeResult = TerminalSession;\ntype TerminalOutputResult = TerminalOutputResponse;\ntype TerminalRestartResult = TerminalSession;\ninterface TerminalsArea {\n close(args: TerminalCloseArgs): Promise;\n create(args: TerminalCreateArgs): Promise;\n get(args: TerminalGetArgs): Promise;\n input(args: TerminalInputArgs): Promise;\n list(args: TerminalListArgs): Promise;\n output(args: TerminalOutputArgs): Promise;\n rename(args: TerminalRenameArgs): Promise;\n /**\n * Replace a terminal with a shell at the same scope, size, and title.\n * The original command is not replayed because terminal sessions do not\n * persist launch commands. The replacement has a new terminal ID.\n */\n restart(args: TerminalRestartArgs): Promise;\n resize(args: TerminalResizeArgs): Promise;\n}\n\ninterface ThreadListArgs {\n archived?: boolean;\n excludeSideChats?: boolean;\n sectionId?: string;\n hasParent?: boolean;\n limit?: number;\n offset?: number;\n originKind?: ThreadListQuery[\"originKind\"];\n parentThreadId?: string;\n projectId?: string;\n signal?: AbortSignal;\n sourceThreadId?: string;\n unsectioned?: boolean;\n}\ninterface ThreadSearchArgs extends ThreadSearchQuery {\n signal?: AbortSignal;\n}\ninterface ThreadGetArgs {\n include?: ThreadGetQuery[\"include\"];\n signal?: AbortSignal;\n threadId: string;\n}\ntype ThreadGetResult = ThreadResponse | ThreadWithIncludesResponse;\ntype ThreadListResult = ThreadListResponse;\ntype ThreadSearchResult = ThreadSearchResponse;\ninterface ThreadOutputResponse {\n output: string | null;\n}\ntype ThreadMutationResult = ThreadResponse;\ntype ThreadSpawnResult = ThreadResponse;\ntype ThreadInteractionGetResult = PendingInteraction;\ntype ThreadInteractionListResult = ThreadPendingInteractionsResponse;\ntype ThreadInteractionResolveResult = PendingInteraction;\ntype ThreadInteractionRespondResult = PendingInteraction;\ntype ThreadInteractionCancelResult = PendingInteraction;\ntype ThreadEventsListResult = ThreadEventRow[];\ntype ThreadEventWaitResult = ThreadEventRow | null;\ntype ThreadTimelineResult = ThreadTimelineResponse;\ntype ThreadArchiveResult = ThreadArchiveAllResponse;\ntype ThreadOpenResult = ThreadOpenResponse;\ntype ThreadPaneActionResult = ThreadPaneActionResponse;\ntype ThreadDeleteResult = {\n ok: true;\n};\ntype ThreadSendResult = {\n ok: true;\n};\ntype ThreadStopResult = {\n ok: true;\n};\ntype ThreadUnarchiveResult = {\n ok: true;\n};\ntype ThreadArchiveAllResult = ThreadArchiveAllResponse;\ntype ThreadReadStateResult = ThreadResponse;\ntype ThreadPinOrderResult = ThreadListResponse;\ntype ThreadPromptHistoryResult = PromptHistoryResponse;\ntype ThreadQueuedMessagesResult = ThreadQueuedMessageListResponse;\ntype ThreadQueuedMessageCreateResult = ThreadQueuedMessage;\ntype ThreadQueuedMessageUpdateResult = ThreadQueuedMessage;\ntype ThreadQueuedMessageDeleteResult = {\n ok: true;\n};\ntype ThreadQueuedMessageReorderResult = ThreadQueuedMessageListResponse;\ntype ThreadQueuedMessageSendResult = SendQueuedMessageResponse;\ntype ThreadQueuedMessageGroupBoundaryResult = ThreadQueuedMessageListResponse;\ntype ThreadTabsResult = ThreadTabsResponse;\ntype ThreadTabsUpdateResult = ThreadTabsResponse;\ntype ThreadStorageFilesResult = ThreadStorageFileListResponse;\ntype ThreadStoragePathsResult = ThreadStoragePathListResponse;\ntype ThreadChildSummaryResult = ThreadChildSummaryResponse;\ntype ThreadDefaultExecutionOptionsResult = ResolvedThreadExecutionOptions | null;\ntype ThreadConversationOutlineResult = ThreadConversationOutlineResponse;\ntype ThreadTimelineTurnSummaryDetailsResult = TimelineTurnSummaryDetailsResponse;\ninterface ThreadSpawnBaseArgs extends Omit {\n childOrigin?: CreateThreadRequest[\"childOrigin\"];\n origin?: CreateThreadRequest[\"origin\"];\n originKind?: CreateThreadRequest[\"originKind\"];\n startedOnBehalfOf?: CreateThreadRequest[\"startedOnBehalfOf\"];\n}\ntype ThreadSpawnArgs = ThreadSpawnBaseArgs & ({\n input: CreateThreadRequest[\"input\"];\n prompt?: never;\n} | {\n input?: never;\n prompt: string;\n});\ninterface ThreadUpdateArgs extends UpdateThreadRequest {\n threadId: string;\n}\ninterface ThreadDeleteArgs extends DeleteThreadRequest {\n threadId: string;\n}\ninterface ThreadSendArgs extends SendMessageRequest {\n threadId: string;\n}\ninterface ThreadActionArgs {\n threadId: string;\n}\ninterface ThreadStatusArgs extends ThreadActionArgs {\n signal?: AbortSignal;\n}\ninterface ThreadPromptHistoryArgs extends PromptHistoryQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadPinOrderArgs extends ReorderPinnedThreadRequest {\n threadId: string;\n}\ninterface ThreadQueuedMessageArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadQueuedMessageCreateArgs extends CreateQueuedMessageRequest {\n threadId: string;\n}\ninterface ThreadQueuedMessageUpdateArgs extends ThreadQueuedMessageTargetArgs, UpdateQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageTargetArgs {\n queuedMessageId: string;\n threadId: string;\n}\ninterface ThreadQueuedMessageSendArgs extends ThreadQueuedMessageTargetArgs, SendQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageReorderArgs extends ThreadQueuedMessageTargetArgs, ReorderQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageGroupBoundaryArgs extends SetQueuedMessageGroupBoundaryRequest {\n threadId: string;\n}\ninterface ThreadStorageFilesArgs extends ThreadStorageFilesQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadStoragePathsArgs extends ThreadStoragePathsQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadTimelineTurnSummaryDetailsArgs extends TimelineTurnSummaryDetailsQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadTabsUpdateArgs extends UpdateThreadTabsRequest {\n threadId: string;\n}\ninterface ThreadOpenArgs {\n threadId: string;\n split?: ThreadOpenSplit;\n file: ThreadOpenFile | null;\n}\ninterface ThreadPaneActionArgs {\n action: ThreadPaneAction;\n threadId: string;\n}\ninterface ThreadEventsListArgs {\n afterSeq?: string;\n limit?: string;\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadEventWaitArgs {\n afterSeq?: string;\n signal?: AbortSignal;\n threadId: string;\n type: string;\n waitMs: string;\n}\ninterface ThreadTimelineArgs extends ThreadTimelineQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadOutputArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadInteractionListArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadInteractionTargetArgs {\n interactionId: string;\n threadId: string;\n}\ninterface ThreadInteractionGetArgs extends ThreadInteractionTargetArgs {\n signal?: AbortSignal;\n}\ninterface ThreadInteractionResolveArgs extends ThreadInteractionTargetArgs {\n resolution: PendingInteractionResolution;\n}\ninterface ThreadInteractionRespondArgs extends ThreadInteractionTargetArgs {\n value: JsonValue;\n}\ntype ThreadWaitTarget = {\n kind: \"status\";\n status: ThreadStatus;\n} | {\n kind: \"event\";\n eventType: string;\n};\ninterface ThreadWaitArgs {\n event?: string;\n pollIntervalMs?: number;\n signal?: AbortSignal;\n status?: ThreadStatus;\n threadId: string;\n timeoutMs?: number;\n}\ntype ThreadWaitResult = {\n event: NonNullable;\n matched: true;\n target: Extract;\n threadId: string;\n} | {\n matched: true;\n target: Extract;\n thread: ThreadGetResult;\n threadId: string;\n};\ninterface ThreadInteractionsArea {\n cancel(args: ThreadInteractionTargetArgs): Promise;\n get(args: ThreadInteractionGetArgs): Promise;\n list(args: ThreadInteractionListArgs): Promise;\n resolve(args: ThreadInteractionResolveArgs): Promise;\n respond(args: ThreadInteractionRespondArgs): Promise;\n}\ninterface ThreadEventsArea {\n list(args: ThreadEventsListArgs): Promise;\n wait(args: ThreadEventWaitArgs): Promise;\n}\ninterface ThreadQueuedMessagesArea {\n create(args: ThreadQueuedMessageCreateArgs): Promise;\n delete(args: ThreadQueuedMessageTargetArgs): Promise;\n list(args: ThreadQueuedMessageArgs): Promise;\n reorder(args: ThreadQueuedMessageReorderArgs): Promise;\n send(args: ThreadQueuedMessageSendArgs): Promise;\n setGroupBoundary(args: ThreadQueuedMessageGroupBoundaryArgs): Promise;\n update(args: ThreadQueuedMessageUpdateArgs): Promise;\n}\ninterface ThreadTabsArea {\n get(args: ThreadStatusArgs): Promise;\n update(args: ThreadTabsUpdateArgs): Promise;\n}\ninterface ThreadsArea {\n archive(args: ThreadActionArgs): Promise;\n archiveAll(args: ThreadActionArgs): Promise;\n childSummary(args: ThreadStatusArgs): Promise;\n conversationOutline(args: ThreadStatusArgs): Promise;\n defaultExecutionOptions(args: ThreadStatusArgs): Promise;\n delete(args: ThreadDeleteArgs): Promise;\n events: ThreadEventsArea;\n get(args: ThreadGetArgs): Promise;\n interactions: ThreadInteractionsArea;\n list(args?: ThreadListArgs): Promise;\n markRead(args: ThreadActionArgs): Promise;\n markUnread(args: ThreadActionArgs): Promise;\n open(args: ThreadOpenArgs): Promise;\n paneAction(args: ThreadPaneActionArgs): Promise;\n output(args: ThreadOutputArgs): Promise;\n pin(args: ThreadActionArgs): Promise;\n promptHistory(args: ThreadPromptHistoryArgs): Promise;\n queuedMessages: ThreadQueuedMessagesArea;\n reorderPinned(args: ThreadPinOrderArgs): Promise;\n search(args: ThreadSearchArgs): Promise;\n send(args: ThreadSendArgs): Promise;\n spawn(args: ThreadSpawnArgs): Promise;\n stop(args: ThreadActionArgs): Promise;\n tabs: ThreadTabsArea;\n timeline(args: ThreadTimelineArgs): Promise;\n timelineTurnSummaryDetails(args: ThreadTimelineTurnSummaryDetailsArgs): Promise;\n storageFiles(args: ThreadStorageFilesArgs): Promise;\n storagePaths(args: ThreadStoragePathsArgs): Promise;\n unarchive(args: ThreadActionArgs): Promise;\n unpin(args: ThreadActionArgs): Promise;\n update(args: ThreadUpdateArgs): Promise;\n wait(args: ThreadWaitArgs): Promise;\n}\n\ntype ThreadSectionCreateResult = ThreadSectionResponse;\ntype ThreadSectionUpdateResult = ThreadSectionMutationResponse;\ntype ThreadSectionDeleteResult = ThreadSectionMutationResponse;\ntype ThreadSectionListResult = ThreadSectionResponse[];\ninterface ThreadSectionListArgs {\n signal?: AbortSignal;\n}\ninterface ThreadSectionsArea {\n create(args: CreateThreadSectionRequest): Promise;\n delete(args: DeleteThreadSectionRequest): Promise;\n list(args?: ThreadSectionListArgs): Promise;\n update(args: UpdateThreadSectionRequest): Promise;\n}\n\ninterface BbSdk extends BbRealtime {\n environments: EnvironmentsArea;\n files: FilesArea;\n guide: GuideArea;\n hosts: HostsArea;\n projects: ProjectsArea;\n plugins: PluginsArea;\n providers: ProvidersArea;\n status: StatusArea;\n system: SystemArea;\n terminals: TerminalsArea;\n theme: ThemeArea;\n threadSections: ThreadSectionsArea;\n threads: ThreadsArea;\n}\n\n/**\n * The backend plugin API contract — the `bb` object handed to a plugin's\n * `server.ts` factory (`export default function plugin(bb: BbPluginApi)`).\n *\n * Types only: the implementation lives in the BB server\n * (apps/server/src/services/plugins/plugin-api.ts), which imports these\n * shapes so the contract and the implementation cannot drift. Plugin authors\n * import them type-only (`import type { BbPluginApi } from\n * \"@bb/plugin-sdk\"`); the import is erased when BB loads the file.\n *\n * Runtime classes stay host-side. NeedsConfigurationError in particular is\n * matched by NAME, so plugin code needs no runtime import:\n * `throw Object.assign(new Error(msg), { name: \"NeedsConfigurationError\" })`.\n */\ninterface PluginLogger {\n debug(message: string): void;\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n/**\n * Declarative settings descriptors (`bb.settings.define`). Deliberately plain\n * data — not zod — so the host can render settings forms and the CLI can\n * parse values without executing plugin code.\n */\ntype PluginSettingDescriptor = {\n type: \"string\";\n label: string;\n description?: string;\n /** Stored in a 0600 file under /plugins//secrets/, never in the db or sent to the frontend. */\n secret?: true;\n default?: string;\n} | {\n type: \"boolean\";\n label: string;\n description?: string;\n default?: boolean;\n} | {\n type: \"select\";\n label: string;\n description?: string;\n options: string[];\n default?: string;\n} | {\n type: \"project\";\n label: string;\n description?: string;\n default?: string;\n};\ntype PluginSettingDescriptors = Record;\ntype PluginSettingValue = string | boolean;\n/** `default` present → non-optional value; absent → `T | undefined`. */\ntype PluginSettingsValues> = {\n [K in keyof Ds]: Ds[K] extends {\n default: string | boolean;\n } ? PluginSettingValueOf : PluginSettingValueOf | undefined;\n};\ntype PluginSettingValueOf = D extends {\n type: \"boolean\";\n} ? boolean : string;\ninterface PluginSettingsHandle> {\n /** Load-safe: callable inside the factory. */\n get(): Promise>;\n /** Fires after values change through the settings route/CLI. */\n onChange(listener: (next: PluginSettingsValues, prev: PluginSettingsValues) => void): void;\n}\ninterface PluginSettings {\n define>(descriptors: Ds): PluginSettingsHandle;\n}\ninterface PluginKvStorage {\n get(key: string): Promise;\n set(key: string, value: unknown): Promise;\n delete(key: string): Promise;\n list(prefix?: string): Promise;\n}\ninterface PluginStorage {\n /** Namespaced JSON key-value rows in bb.db; values ≤256KB each. */\n kv: PluginKvStorage;\n /**\n * Open (or reuse the path of) the plugin's own SQLite database at\n * /plugins//data.db — the server's better-sqlite3, WAL mode,\n * busy_timeout 5000. Handles are host-tracked and closed on\n * dispose/reload; a closed handle throws on use.\n */\n database(): Database.Database;\n /**\n * Ordered-statement migration helper: statement index = migration id in a\n * `_bb_migrations` table; unapplied statements run in one transaction.\n * Append-only — never reorder or edit shipped statements.\n */\n migrate(db: Database.Database, statements: string[]): void;\n}\n/**\n * Thread lifecycle events a plugin can observe (design §4.5). Observe-only:\n * handlers run fire-and-forget after the transition is applied and can never\n * block or veto it. `thread` is the same public DTO GET /threads/:id serves.\n */\ninterface PluginThreadEventPayloads {\n /** Fired after a thread row is created. */\n \"thread.created\": {\n thread: ThreadResponse;\n };\n /** Fired when a thread transitions into `active`. */\n \"thread.active\": {\n thread: ThreadResponse;\n };\n /** Fired when a thread transitions into `idle`. `lastAssistantText` is\n * assembled the same way GET /threads/:id/output is. */\n \"thread.idle\": {\n thread: ThreadResponse;\n lastAssistantText: string | null;\n };\n /** Fired when a thread transitions into `error`. `error` is the latest\n * system/error event message, when one exists. */\n \"thread.failed\": {\n thread: ThreadResponse;\n error: string | null;\n };\n /** Fired after a thread is soft-deleted. */\n \"thread.deleted\": {\n thread: ThreadResponse;\n };\n}\ntype PluginThreadEventName = keyof PluginThreadEventPayloads;\ntype PluginThreadEventHandler = (payload: PluginThreadEventPayloads[E]) => void | Promise;\ntype PluginHttpAuthMode = \"local\" | \"token\" | \"none\";\ntype PluginHttpHandler = (context: Context) => Response | Promise;\ninterface PluginHttp {\n /**\n * Register an HTTP route, mounted at\n * `/api/v1/plugins//http/`. Auth modes (default \"local\"):\n * - \"local\": Origin/Host must be a local BB app origin; non-GET requires\n * content-type application/json (forces a CORS preflight).\n * - \"token\": requires the per-plugin token (`bb plugin token `) via\n * the x-bb-plugin-token header or ?token=.\n * - \"none\": no checks — only for signature-verified webhooks.\n */\n route(method: string, path: string, handler: PluginHttpHandler, opts?: {\n auth?: PluginHttpAuthMode;\n }): void;\n}\ninterface PluginRpc {\n /**\n * Register a Standard Schema-driven rpc contract and its inferred handlers,\n * served at POST\n * `/api/v1/plugins//rpc/` with \"local\" auth semantics. The\n * host validates input before invocation and output before strict JSON\n * serialization. The response is `{ ok: true, result }` or\n * `{ ok: false, error: { code, message, issues? } }`.\n */\n register(contract: Contract, handlers: PluginRpcHandlers): void;\n}\ninterface PluginRealtime {\n /**\n * Broadcast an ephemeral `plugin-signal` WS message\n * `{ pluginId, channel, payload }` to every connected client (V1 has no\n * per-channel subscriptions). `payload` must be JSON-serializable;\n * `undefined` is normalized to `null`. Nothing is persisted.\n */\n publish(channel: string, payload: unknown): void;\n}\ninterface PluginBackground {\n /**\n * Register a long-lived background service. `start` runs after the\n * factory completes and should resolve when `signal` aborts\n * (dispose/reload/disable/shutdown). A crash restarts it with capped\n * exponential backoff; throwing NeedsConfigurationError marks the plugin\n * `needs-configuration` and stops restarting until the next load.\n */\n service(name: string, service: {\n start(signal: AbortSignal): void | Promise;\n }): void;\n /**\n * Register a cron schedule (5-field expression, server-local time). The\n * durable row keyed (pluginId, name) is upserted at load; the periodic\n * sweep claims due rows with a CAS on next_run_at, but only while this\n * plugin is loaded. Failures land in last_status/last_error, visible in\n * `bb plugin list`.\n */\n schedule(name: string, cron: string, fn: () => void | Promise): void;\n}\ninterface PluginCliCommandInfo {\n name: string;\n summary: string;\n usage: string;\n}\n/** Context forwarded from the invoking CLI when known; all fields optional. */\ninterface PluginCliContext {\n cwd?: string;\n threadId?: string;\n projectId?: string;\n /** Aborted when the invoking CLI HTTP request disconnects. */\n signal?: AbortSignal;\n}\ntype PluginInteractionCancelReason = \"user\" | \"request-aborted\" | \"thread-stopped\" | \"thread-deleted\" | \"plugin-disposed\" | \"server-restarted\" | \"timeout\";\ntype PluginInteractionResult = {\n outcome: \"submitted\";\n value: JsonValue$1;\n} | {\n outcome: \"cancelled\";\n reason: PluginInteractionCancelReason;\n};\ninterface PluginInteractionRequest {\n threadId: string;\n rendererId: string;\n title: string;\n payload: JsonValue$1;\n /** Defaults to ten minutes; capped at one hour. */\n timeoutMs?: number;\n}\ninterface PluginCliResult {\n exitCode: number;\n stdout?: string;\n stderr?: string;\n}\n/**\n * Maximum combined UTF-8 bytes accepted from plugin CLI stdout and stderr.\n * This is the shared source of truth for production and the testing harness.\n */\ndeclare const PLUGIN_CLI_OUTPUT_MAX_BYTES: number;\ninterface PluginCliOutputLimitError {\n code: \"plugin_cli_output_too_large\";\n message: string;\n maxBytes: number;\n stdoutBytes: number;\n stderrBytes: number;\n totalBytes: number;\n}\n/** Normalized host result returned by the plugin CLI HTTP/testing boundary. */\ninterface PluginCliExecutionResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n error?: PluginCliOutputLimitError;\n}\ninterface PluginCliRegistration {\n /** Top-level command name (`bb …`): lowercase [a-z0-9-]+, and not\n * a core bb command (see RESERVED_BB_CLI_COMMANDS in the server). */\n name: string;\n summary: string;\n /** Subcommand metadata rendered in help and the plugin-commands skill\n * without executing plugin code. Parsing argv is plugin-owned. */\n commands?: PluginCliCommandInfo[];\n run(argv: string[], ctx: PluginCliContext): PluginCliResult | Promise;\n}\ninterface PluginCli {\n /**\n * Register this plugin's `bb` subcommand. One registration per factory\n * execution; a repeated call is rejected. Core bb commands always win\n * name collisions; reserved names are rejected at registration.\n */\n register(registration: PluginCliRegistration): void;\n}\n/** Per-turn context handed to bb.agents context providers (design §4.4). */\n/** MCP-style content parts a native tool may return (design §4.4). */\ntype PluginAgentToolContentPart = {\n type: \"text\";\n text: string;\n} | {\n type: \"image\";\n data: string;\n mimeType: string;\n};\ntype PluginAgentToolResult = string | {\n content: PluginAgentToolContentPart[];\n isError?: boolean;\n};\n/** Per-call context handed to a native tool's execute (design §4.4). */\ninterface PluginAgentToolContext {\n threadId: string;\n projectId: string;\n /** The tool-call request's abort signal (aborts if the daemon round-trip\n * is torn down mid-call). */\n signal: AbortSignal;\n}\ninterface PluginAgentToolRegistrationBase {\n /** Tool name shown to the model: [a-zA-Z0-9_-]+, unique across plugins,\n * and not a built-in dynamic tool (see RESERVED_AGENT_TOOL_NAMES in the\n * server). */\n name: string;\n description: string;\n /**\n * Optional usage snippet appended to the thread instructions whenever\n * this tool is in the session's tool set (mirrors the built-in\n * update_environment_directory guidance). Limited to 4096 characters.\n */\n instructions?: string;\n}\n/** Stable, plain-data context resolved by the server for one agent session. */\ninterface PluginAgentConfigurationContext {\n thread: {\n id: string;\n title: string | null;\n parentThreadId: string | null;\n sourceThreadId: string | null;\n };\n project: {\n id: string;\n kind: \"standard\" | \"personal\";\n name: string;\n gitRemoteUrl: string | null;\n };\n environment: {\n id: string;\n name: string | null;\n path: string | null;\n workspaceProvisionType: \"unmanaged\" | \"managed-worktree\" | \"personal\";\n branchName: string | null;\n };\n host: {\n id: string;\n name: string;\n };\n provider: {\n id: string;\n model: string;\n };\n sideChat: boolean;\n origin: {\n kind: \"fork\" | \"side-chat\" | null;\n pluginId: string | null;\n };\n}\n/** Object form of a {@link PluginAgentConfiguration} tools entry: selects a\n * registered tool and overrides the parameter schema advertised to the\n * provider for this resolution only. */\ninterface PluginAgentToolSelection {\n /** Name of a tool registered by this plugin via `registerTool`. */\n name: string;\n /** JSON-schema object (root `type: \"object\"`, JSON-serializable, at most\n * 128 KiB serialized) sent to the provider in place of the registered\n * parameter schema. Execution-side validation still runs the registered\n * parameters, so the override must only narrow what the registered schema\n * already accepts. */\n parameters: Record;\n}\n/** Per-resolution selection returned by {@link PluginAgents.configure}. */\ninterface PluginAgentConfiguration {\n /** Tool names registered by this plugin, or {@link PluginAgentToolSelection}\n * entries to also override a tool's advertised parameter schema for this\n * resolution. Duplicate or unknown names, or an invalid override, reject\n * this plugin's complete selection for the resolution. */\n tools: Array;\n /** Skill frontmatter names from this plugin's manifest skill roots.\n * Duplicate or unknown names reject this plugin's complete selection. */\n skills: string[];\n /** Optional dynamic instructions. Output is truncated to 4096 characters. */\n instructions?: string;\n}\ninterface PluginAgents {\n /**\n * Select this plugin's statically registered tools and manifest skills for\n * each thread/session resolution, with optional dynamic instructions. The\n * callback is synchronous and runs at `thread.start` / `turn.submit`; it\n * never rebuilds registrations. Exactly one callback may be registered per\n * factory execution. A throw, malformed result, duplicate id, unknown id,\n * or more than 256 tool/skill ids fails closed for this plugin only.\n *\n * Tools take effect when the provider session is next started or resumed;\n * an already-running session is not hot-mutated. Instructions are resolved\n * for the next turn. Skill changes follow BB's environment runtime policy:\n * a busy runtime keeps its current catalog until a safe relaunch. Side-chat\n * threads receive `sideChat: true`, and their returned tool, skill, and\n * dynamic-instruction selections apply at the same boundaries. Independent\n * side-chat safety policy (such as permission escalation) is unchanged.\n */\n configure(provider: (context: PluginAgentConfigurationContext) => PluginAgentConfiguration): void;\n /**\n * Register a native dynamic tool (design §4.4). `parameters` is either a\n * zod schema (validated per call; execute receives the parsed value) or a\n * plain JSON-schema object (no validation; execute receives the raw\n * arguments as `unknown`). Tool-set changes apply on the NEXT session\n * start — a tool registered mid-session is not hot-added to running\n * provider sessions. A second registration of the same name within this\n * plugin is rejected; a name already registered by another plugin is\n * rejected and surfaced as this plugin's status detail.\n */\n registerTool(tool: PluginAgentToolRegistrationBase & {\n parameters: Schema;\n execute(params: z.output, ctx: PluginAgentToolContext): PluginAgentToolResult | Promise;\n }): void;\n registerTool(tool: PluginAgentToolRegistrationBase & {\n /** Raw JSON-schema escape hatch; params arrive unvalidated. */\n parameters: Record;\n execute(params: unknown, ctx: PluginAgentToolContext): PluginAgentToolResult | Promise;\n }): void;\n /**\n * Contribute a dynamic section appended to thread instructions. The\n * provider runs when a thread's runtime command config is resolved\n * (thread.start / turn.submit); return null to contribute nothing for\n * that resolution. Must be synchronous and fast — it sits on the\n * thread-start path. Output longer than 4096 characters is truncated; a\n * throwing provider is logged against the plugin and contributes nothing.\n * A repeated registration within one factory execution is rejected.\n * This legacy contribution is not applied to side-chat threads; use\n * configure() when sideChat-aware dynamic instructions are required.\n */\n contributeInstructions(provider: (ctx: {\n threadId: string;\n projectId: string;\n }) => string | null): void;\n}\ninterface PluginThreadActionContext {\n threadId: string;\n projectId: string;\n}\ninterface PluginThreadActionToast {\n kind: \"success\" | \"error\" | \"info\";\n message: string;\n}\ntype PluginThreadActionResult = void | {\n toast?: PluginThreadActionToast;\n};\ninterface PluginThreadActionRegistration {\n /** Unique within this plugin: [a-zA-Z0-9_-]+ (becomes a URL segment). */\n id: string;\n /** Button label rendered in the thread header. */\n title: string;\n /** Optional icon name; the host falls back to a generic icon. */\n icon?: string;\n /** Optional confirmation prompt the host shows before running. */\n confirm?: string;\n /**\n * Runs server-side when the user clicks the action. The host shows a\n * pending state while in flight, the returned toast on completion, and an\n * automatic error toast when this throws.\n */\n run(ctx: PluginThreadActionContext): PluginThreadActionResult | Promise;\n}\ntype PluginMentionTrigger = \"@\" | \"#\" | \"$\" | \"!\" | \"~\";\n/** Search context handed to a mention provider (design §4.9). `projectId`/\n * `threadId` are null when the composer has not committed one yet. */\ninterface PluginMentionSearchContext {\n trigger: PluginMentionTrigger;\n query: string;\n projectId: string | null;\n threadId: string | null;\n}\n/** One row a mention provider returns from `search`. `id` is the provider's\n * own item id — the host namespaces it before it reaches the wire. */\ninterface PluginMentionItem {\n id: string;\n title: string;\n subtitle?: string;\n icon?: string;\n}\ninterface PluginMentionProviderRegistration {\n /** Unique within this plugin: [a-zA-Z0-9_-]+ (no \":\" — the host composes\n * wire item ids as \":\"). */\n id: string;\n /** Section label shown above this provider's rows in the mention menu. */\n label: string;\n /**\n * Composer trigger characters this provider should answer. Omit to use the\n * default `@` mention trigger. Valid triggers are `@`, `#`, `$`, `!`, and `~`.\n */\n triggers?: readonly PluginMentionTrigger[];\n /**\n * Runs server-side as the user types after one of this provider's triggers\n * in the composer. Each call is time-boxed (2s) and failure-isolated: a slow\n * or throwing provider contributes an empty list — it can never break the\n * mention menu.\n */\n search(ctx: PluginMentionSearchContext): PluginMentionItem[] | Promise;\n /**\n * Resolves one picked item into agent context, called once per unique\n * item at message send time. The returned `context` is attached to the\n * message as an agent-visible (user-hidden) prompt input. Throwing blocks\n * the send with a visible error.\n */\n resolve(itemId: string): {\n context: string;\n } | Promise<{\n context: string;\n }>;\n}\ninterface PluginUi {\n /** Block until the app submits or cancels a plugin-owned composer form. */\n requestInput(request: PluginInteractionRequest, options?: {\n signal?: AbortSignal;\n }): Promise;\n /**\n * Register a thread action rendered in the shipped app's thread header\n * (design §4.9). Multiple actions per plugin; ids must be unique within\n * the plugin. Invoked via POST /plugins/:id/actions/:actionId.\n */\n registerThreadAction(action: PluginThreadActionRegistration): void;\n /**\n * Register a mention provider for the shipped app's composer (design §4.9).\n * Providers default to the `@` trigger and may opt into `#`, `$`, `!`, or\n * `~` with `triggers`. Items group under `label` in the mention menu; a\n * picked item becomes a `{ kind: \"plugin\" }` mention resource whose context\n * is resolved once at send time. Multiple providers per plugin; ids must be\n * unique within the plugin.\n */\n registerMentionProvider(provider: PluginMentionProviderRegistration): void;\n}\ninterface PluginEvents {\n /**\n * Add a thread lifecycle listener. Multiple listeners for the same event are\n * additive and run independently in registration order.\n */\n on(event: E, handler: PluginThreadEventHandler): void;\n}\ninterface PluginServerApi {\n /**\n * This BB server's own loopback base URL (e.g. \"http://127.0.0.1:38886\"),\n * which serves the SPA + /api + /ws. For plugins that proxy or relay\n * traffic back to the server itself (e.g. a tunnel). Bind-gated like\n * `bb.sdk`: reading it before the server is listening throws, so prefer\n * reading it from handlers, services, and timers.\n */\n readonly loopbackBaseUrl: string;\n}\ninterface PluginSharedPortTunnelIdentity {\n /** Gate routing label assigned to this machine. */\n label: string;\n /** Gate apex without a scheme, e.g. \"getbb.app\". */\n baseDomain: string;\n}\ninterface PluginHosts {\n /**\n * Ensure this enrolled host has a gate label and return its read-only public\n * identity. The daemon chooses the trusted gate and desired label; plugins\n * cannot influence either credential-bearing destination.\n */\n ensureSharedPortTunnel(hostId: string): Promise;\n /**\n * Replace this plugin's desired shared-loopback ports for one host. The\n * server aggregates declarations, owns generations, and delivers the\n * resulting set to that host's daemon. Tunnel identity is deliberately not\n * accepted here: it is owned by the daemon's trusted enrollment.\n */\n declareSharedPorts(hostId: string, ports: readonly number[]): void;\n}\ninterface PluginStatusApi {\n /**\n * Mark this plugin `needs-configuration` (with a message shown in\n * `bb plugin list` and the UI) instead of failing — e.g. a factory or\n * service that finds no API key configured. Cleared on the next load;\n * saving settings does not auto-reload in V1, so ask the user to\n * `bb plugin reload ` after configuring.\n */\n needsConfiguration(message: string): void;\n}\n/**\n * The API object handed to a plugin's factory (design §4). Implemented by\n * the BB server; this contract is what plugin `server.ts` files compile\n * against.\n */\ninterface BbPluginApi {\n /** The plugin's own id (namespaces storage, routes, commands). */\n readonly pluginId: string;\n /** Leveled, plugin-scoped logger. */\n readonly log: PluginLogger;\n /** Declarative settings (design §4.2). */\n readonly settings: PluginSettings;\n /** Namespaced KV + per-plugin database (design §4.3). */\n readonly storage: PluginStorage;\n /** HTTP routes under /api/v1/plugins//http/* (design §4.6). */\n readonly http: PluginHttp;\n /** RPC methods under /api/v1/plugins//rpc/ (design §4.6). */\n readonly rpc: PluginRpc;\n /** Ephemeral push to connected frontends (design §4.7). */\n readonly realtime: PluginRealtime;\n /** Long-lived services + cron schedules (design §4.8). */\n readonly background: PluginBackground;\n /** Agent-facing `bb` CLI subcommand (design §4.4). */\n readonly cli: PluginCli;\n /** Per-turn agent context contributions (design §4.4). */\n readonly agents: PluginAgents;\n /** Host-rendered UI contributions (design §4.9). */\n readonly ui: PluginUi;\n /** Additive plugin lifecycle listeners (design §4.5). */\n readonly events: PluginEvents;\n /** Plugin-reported status (needs-configuration). */\n readonly status: PluginStatusApi;\n /** Read-only facts about the running server (loopback base URL). */\n readonly server: PluginServerApi;\n /** Server-to-daemon host control-plane declarations. */\n readonly hosts: PluginHosts;\n /**\n * The full BB SDK, bound to this server over loopback (design §4.1).\n * Bind-gated: reading this before the host binds the SDK throws. The real\n * server binds it before loading plugins, so it is available from the\n * moment factories run there — but isolated harnesses may not, so prefer\n * using it from handlers, services, and timers for portability.\n * `threads.spawn` defaults `origin` to \"plugin\" and `originPluginId` to\n * this plugin's id so spawned threads are attributed automatically.\n */\n readonly sdk: BbSdk;\n /**\n * Register cleanup to run on reload/disable/shutdown. Hooks run LIFO.\n * The sanctioned place to clear timers and close connections.\n */\n onDispose(hook: () => void | Promise): void;\n}\n\nexport { PLUGIN_CLI_OUTPUT_MAX_BYTES, defineRpcContract };\nexport type { BbContext, BbNavigate, BbPluginApi, JsonValue$1 as JsonValue, PluginAgentConfiguration, PluginAgentConfigurationContext, PluginAgentToolContentPart, PluginAgentToolContext, PluginAgentToolRegistrationBase, PluginAgentToolResult, PluginAgentToolSelection, PluginAgents, PluginAppBuilder, PluginAppDefinition, PluginAppSetup, PluginAppSlots, PluginBackground, PluginCli, PluginCliCommandInfo, PluginCliContext, PluginCliExecutionResult, PluginCliOutputLimitError, PluginCliRegistration, PluginCliResult, PluginComposerAccessoryProps, PluginComposerAccessoryRegistration, PluginComposerApi, PluginComposerMention, PluginComposerScope, PluginEvents, PluginFileOpenerProps, PluginFileOpenerRegistration, PluginFileOpenerSource, PluginHomepageSectionProps, PluginHomepageSectionRegistration, PluginHosts, PluginHttp, PluginHttpAuthMode, PluginHttpHandler, PluginInteractionCancelReason, PluginInteractionRequest, PluginInteractionResult, PluginKvStorage, PluginLogger, PluginMentionItem, PluginMentionProviderRegistration, PluginMentionSearchContext, PluginMentionTrigger, PluginMessageDirectiveMessage, PluginMessageDirectiveOpenThreadPanel, PluginMessageDirectiveOpenWorkspaceFile, PluginMessageDirectiveProps, PluginMessageDirectiveRegistration, PluginMessageDirectiveThreadPanelOptions, 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 };\n"; +export const PLUGIN_SDK_DTS = "// Portable type declarations for `@bb/plugin-sdk`. Unpublished BB\n// workspace contracts are flattened; public subpaths may reuse the\n// package root without requiring any other @bb/* package.\n//\n// Confused by the API, or need a symbol that isn't here? Clone the BB repo\n// and read the real source: https://github.com/ymichael/bb\n\nimport { ComponentType } from 'react';\nimport Database from 'better-sqlite3';\nimport { Context } from 'hono';\nimport * as z from 'zod';\nimport { z as z$1 } from 'zod';\n\n/**\n * A value that survives a JSON round trip without coercion or data loss.\n *\n * Host boundaries still validate values at runtime because TypeScript cannot\n * exclude non-finite numbers and plugin bundles can bypass static types.\n */\ntype JsonValue$1 = string | number | boolean | null | JsonValue$1[] | {\n [key: string]: JsonValue$1;\n};\n\n/** A JSON-safe path segment reported by a Standard Schema validation issue. */\ntype PluginRpcIssuePathSegment = string | number;\n/** Validator-neutral validation detail carried by an RPC error envelope. */\ninterface PluginRpcValidationIssue {\n message: string;\n path?: PluginRpcIssuePathSegment[];\n}\n/** Stable wire error categories for plugin RPC. */\ntype PluginRpcErrorCode = \"invalid_json\" | \"invalid_input\" | \"handler_error\" | \"invalid_output\" | \"non_json_result\" | \"unknown_method\";\n/** Structured RPC failure returned as `{ ok: false, error }`. */\ninterface PluginRpcError {\n code: PluginRpcErrorCode;\n message: string;\n issues?: PluginRpcValidationIssue[];\n}\n/**\n * The validator-neutral subset of Standard Schema v1 used by plugin RPC.\n * Zod 4 schemas implement this interface directly; other validators can do\n * the same without becoming part of BB's public protocol.\n */\ninterface StandardSchemaV1 {\n readonly \"~standard\": {\n readonly version: 1;\n readonly vendor: string;\n readonly validate: (value: unknown) => StandardSchemaV1Result | Promise>;\n readonly types?: {\n readonly input: Input;\n readonly output: Output;\n };\n };\n}\ntype StandardSchemaV1Result = {\n readonly value: Output;\n readonly issues?: undefined;\n} | {\n readonly issues: readonly StandardSchemaV1Issue[];\n};\ninterface StandardSchemaV1Issue {\n readonly message: string;\n readonly path?: PropertyKey | readonly (PropertyKey | {\n readonly key: PropertyKey;\n })[];\n}\ntype StandardSchemaV1InferInput = NonNullable[\"input\"];\ntype StandardSchemaV1InferOutput = NonNullable[\"output\"];\ninterface PluginRpcMethodContract {\n readonly input: InputSchema;\n readonly output: OutputSchema;\n}\ntype PluginRpcContract = Readonly>;\n/** Define a shared RPC contract while preserving exact method/schema types. */\ndeclare function defineRpcContract(contract: Contract): Contract;\ntype PluginRpcHandlers = {\n [Method in keyof Contract]: (input: StandardSchemaV1InferOutput) => StandardSchemaV1InferInput | Promise>;\n};\ntype PluginRpcCallInput = StandardSchemaV1InferInput;\ntype PluginRpcCallArgs = null extends PluginRpcCallInput ? [input?: PluginRpcCallInput] : [input: PluginRpcCallInput];\ntype PluginRpcResult = StandardSchemaV1InferOutput;\n\n/**\n * The `@bb/plugin-sdk/app` contract (plugin design §5.2) — pure types with no\n * side effects. The BB app imports these to keep its real implementation in\n * sync (`satisfies PluginSdkApp`). Plugin authors import the same shapes through\n * `@bb/plugin-sdk/app`.\n *\n * Per-slot props are versioned contracts: additive-only within an SDK major.\n */\n/** Props passed to a `homepageSection` component. */\ninterface PluginHomepageSectionProps {\n /** Project in view on the compose surface; null when none is selected. */\n projectId: string | null;\n}\n/**\n * Props passed to a `settingsSection` component.\n *\n * Deliberately empty in V1; versioned additive like the other slot props.\n */\ninterface PluginSettingsSectionProps {\n}\n/** Props passed to a `navPanel` component (it owns its whole route). */\ninterface PluginNavPanelProps {\n /**\n * The route remainder after the panel root, \"\" at the root. The panel's\n * route is `/plugins///*`, so a deep link like\n * `/plugins/notes/notes/work/ideas.md` renders the panel with\n * `subPath: \"work/ideas.md\"`. Navigate within the panel via\n * `useBbNavigate().toPluginPanel(path, { subPath })` — browser\n * back/forward then walks panel-internal history.\n */\n subPath: string;\n}\n/** Props passed to a panel tab opened by a `threadPanelAction`. */\ninterface PluginThreadPanelProps {\n threadId: string;\n /**\n * The JSON value the action's `openPanel` call passed (round-tripped\n * through persistence, so the tab restores across reloads); null when the\n * action opened the panel without params.\n */\n params: JsonValue$1 | null;\n}\n/** Props passed to a `composerAccessory` component. */\ninterface PluginComposerAccessoryProps {\n projectId: string | null;\n threadId: string | null;\n}\ninterface PluginPendingInteractionView {\n id: string;\n threadId: string;\n title: string;\n payload: JsonValue$1;\n createdAt: number;\n expiresAt: number | null;\n}\ninterface PluginPendingInteractionProps {\n interaction: PluginPendingInteractionView;\n submit(value: JsonValue$1): Promise;\n cancel(): Promise;\n}\n/**\n * Props for a `sidebarFooterAction` — host-rendered (no plugin component).\n * Deliberately empty; the registration's `run` carries the behavior.\n */\ninterface PluginSidebarFooterActionProps {\n}\n/**\n * Where a file being opened by a `fileOpener` lives. `path` semantics follow\n * the source: workspace paths are relative to the environment's worktree,\n * thread-storage paths are relative to the thread's storage root, host paths\n * are absolute on the thread's host.\n */\ninterface PluginFileOpenerSource {\n kind: \"workspace\" | \"host\" | \"thread-storage\";\n threadId: string | null;\n environmentId: string | null;\n projectId: string | null;\n}\n/** Props passed to a `fileOpener` component (rendered as a panel file tab). */\ninterface PluginFileOpenerProps {\n path: string;\n source: PluginFileOpenerSource;\n}\n/**\n * Message context passed to a `messageDirective` component — the assistant\n * (or nested agent) message that contained the directive.\n */\ninterface PluginMessageDirectiveMessage {\n id: string;\n threadId: string;\n turnId: string | null;\n projectId: string | null;\n}\n/**\n * Open a worktree-relative file in the host's workspace file viewer. Returns\n * true when the host accepted the path; false when the path is invalid or the\n * viewer declined it.\n */\ntype PluginMessageDirectiveOpenWorkspaceFile = (path: string) => boolean;\ninterface PluginMessageDirectiveThreadPanelOptions {\n /** A `threadPanelAction` id registered by this same plugin. */\n actionId: string;\n title?: string;\n params?: JsonValue$1;\n}\n/** Open this plugin's registered action in the current thread side panel. */\ntype PluginMessageDirectiveOpenThreadPanel = (options: PluginMessageDirectiveThreadPanelOptions) => boolean;\n/**\n * Props passed to a `messageDirective` component. Attributes are untrusted\n * strings parsed from the directive; the plugin validates its own fields.\n */\ninterface PluginMessageDirectiveProps {\n /** Parsed, untrusted directive attributes (e.g. `{ file: \"demo.html\" }`). */\n attributes: Readonly>;\n /** Original directive source text (useful for diagnostics / crash fallback). */\n source: string;\n message: PluginMessageDirectiveMessage;\n /**\n * Opens a worktree-relative file in the host's workspace file viewer. Null\n * when the message surface has no workspace viewer available.\n */\n openWorkspaceFile: PluginMessageDirectiveOpenWorkspaceFile | null;\n /**\n * Opens one of this plugin's own `threadPanelAction` components in the\n * current thread side panel. Omitted by older hosts; null on message\n * surfaces without a thread panel.\n */\n openThreadPanel?: PluginMessageDirectiveOpenThreadPanel | null;\n}\ninterface PluginHomepageSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n component: ComponentType;\n}\ninterface PluginSettingsSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Optional host-rendered section heading. */\n title?: string;\n /**\n * Optional one-line host-rendered subheading under `title`, in the built-in\n * SettingsSection idiom (ignored when `title` is absent).\n */\n description?: string;\n component: ComponentType;\n}\ninterface PluginNavPanelRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /** URL segment under `/plugins//`; letters, digits, `-`, `_`. */\n path: string;\n component: ComponentType;\n /**\n * Optional component rendered on the right side of the shared title bar\n * (e.g. a sync button or a count). Contained separately from the body: a\n * throwing headerContent is hidden without breaking the title bar.\n */\n headerContent?: ComponentType;\n}\n/** Context handed to a `threadPanelAction`'s `run`. */\ninterface PluginThreadPanelActionContext {\n /** The thread whose panel launcher invoked the action. */\n threadId: string;\n /**\n * Open a tab in the thread's side panel rendering this action's\n * `component`. `title` labels the tab (default: the action's `title`);\n * `params` must be JSON-serializable — it is persisted with the tab and\n * reaches the component as its `params` prop. Opening with params\n * identical to an already-open tab of this action focuses that tab\n * (updating its title) instead of duplicating it. May be called more than\n * once (different params ⇒ multiple tabs) or not at all.\n */\n openPanel(options?: {\n title?: string;\n params?: JsonValue$1;\n }): void;\n}\ninterface PluginThreadPanelActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label of the action row in the panel's new-tab launcher. */\n title: string;\n /**\n * Icon hint (BB icon name) used when the plugin ships no logo; the\n * launcher row and opened tabs prefer the plugin's logo.\n */\n icon?: string;\n /** Rendered inside every panel tab this action opens. */\n component: ComponentType;\n /**\n * Runs when the user activates the action: call your RPC methods, show a\n * toast, and/or open panel tabs via `context.openPanel`. Omitted =\n * immediately open a panel tab with defaults. Errors (sync or async) are\n * contained and logged; they never break the launcher.\n */\n run?(context: PluginThreadPanelActionContext): void | Promise;\n}\ninterface PluginComposerAccessoryRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n component: ComponentType;\n}\ninterface PluginPendingInteractionRegistration {\n /** Matches `rendererId` passed to `bb.ui.requestInput`. */\n id: string;\n component: ComponentType;\n}\n/** Context handed to a `sidebarFooterAction`'s `run`. */\ninterface PluginSidebarFooterActionContext {\n /**\n * Navigate to this plugin's Settings detail page\n * (`/settings/plugins/`), where declarative settings and\n * `settingsSection` slots render.\n */\n openSettings(): void;\n}\n/**\n * An icon button in the app sidebar footer (next to Settings / bug report).\n * Host-rendered for consistent chrome — plugins supply icon, label, and\n * `run` behavior only.\n */\ninterface PluginSidebarFooterActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Tooltip and accessible label for the icon button. */\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /**\n * Runs when the user activates the action (e.g. call `openSettings()`,\n * open a panel via other surfaces, toast). Errors (sync or async) are\n * contained and logged; they never break the sidebar.\n */\n run(context: PluginSidebarFooterActionContext): void | Promise;\n}\n/**\n * Register this plugin as a viewer/editor for file extensions. The user\n * picks (and can set as default) an opener per extension via the file tab's\n * \"Open with\" menu; matching files opened in the panel then render\n * `component` in a plugin tab instead of the built-in preview. Applies to\n * working-tree, host, and thread-storage files — never to git-ref snapshots\n * (diff views always use the built-in preview). The built-in preview stays\n * one menu click away, and a missing/disabled opener falls back to it.\n */\ninterface PluginFileOpenerRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label in the \"Open with\" menu (e.g. \"Notes editor\"). */\n title: string;\n /** Lowercase extensions without the dot (e.g. [\"md\", \"mdx\"]). */\n extensions: readonly string[];\n component: ComponentType;\n}\n/**\n * Register a leaf message directive rendered inside assistant (and nested\n * agent) message Markdown. `id` is the directive name: `inline-vis` matches\n * `::inline-vis{file=\"demo.html\"}`.\n */\ninterface PluginMessageDirectiveRegistration {\n /**\n * The directive name. Lowercase kebab-case beginning with a letter.\n */\n id: string;\n component: ComponentType;\n}\ninterface PluginAppSlots {\n homepageSection(registration: PluginHomepageSectionRegistration): void;\n settingsSection(registration: PluginSettingsSectionRegistration): void;\n navPanel(registration: PluginNavPanelRegistration): void;\n threadPanelAction(registration: PluginThreadPanelActionRegistration): void;\n composerAccessory(registration: PluginComposerAccessoryRegistration): void;\n pendingInteraction(registration: PluginPendingInteractionRegistration): void;\n sidebarFooterAction(registration: PluginSidebarFooterActionRegistration): void;\n fileOpener(registration: PluginFileOpenerRegistration): void;\n messageDirective(registration: PluginMessageDirectiveRegistration): void;\n}\ninterface PluginAppBuilder {\n slots: PluginAppSlots;\n}\ntype PluginAppSetup = (app: PluginAppBuilder) => void;\n/**\n * The opaque product of `definePluginApp` — a plugin's `app.tsx` default\n * export. The host re-runs `setup` against a fresh collector on every\n * (re)interpretation, replacing that plugin's registrations wholesale.\n */\ninterface PluginAppDefinition {\n /** Brand the host checks before interpreting a bundle's default export. */\n readonly __bbPluginApp: true;\n readonly setup: PluginAppSetup;\n}\ninterface PluginRpcClient {\n /**\n * Invoke one of the plugin's `bb.rpc` methods (POST\n * /api/v1/plugins/<id>/rpc/<method>). Resolves with the method's\n * inferred output; rejects with an `Error` carrying the server's message,\n * stable `code`, and validation `issues` when present.\n */\n call>(method: Method, ...args: PluginRpcCallArgs): Promise>;\n}\ninterface PluginSettingsState {\n /**\n * Effective non-secret setting values (secret settings are excluded —\n * read them server-side). Undefined while loading or unavailable.\n */\n values: Record | undefined;\n isLoading: boolean;\n}\n/** State of the app's shared realtime connection to the bb server. */\ntype PluginRealtimeConnectionState = \"connecting\" | \"connected\" | \"reconnecting\";\n/** Where `useComposer()` writes: the active thread's draft or the new-thread draft. */\ntype PluginComposerScope = {\n kind: \"thread\";\n threadId: string;\n} | {\n kind: \"new-thread\";\n projectId: string | null;\n};\n/** An @-mention pill bound to one of the calling plugin's mention providers. */\ninterface PluginComposerMention {\n /** Mention provider id registered by THIS plugin via `bb.ui.registerMentionProvider`. */\n provider: string;\n /** Item id your provider's `resolve` will receive at send time. */\n id: string;\n /** Pill text shown in the composer. */\n label: string;\n}\n/**\n * Programmatic access to the chat composer draft — the same shared draft the\n * built-in \"Add to chat\" affordances (file preview, diff, terminal selections)\n * write to. Inside a thread context writes land in that thread's draft;\n * anywhere else (nav panel, homepage section) they seed the new-thread\n * composer draft, which persists until the user sends or clears it.\n */\ninterface PluginComposerApi {\n scope: PluginComposerScope;\n /** Current plain text for this composer scope. */\n readonly text: string;\n /**\n * Replace the draft's plain text. Attachments are preserved. Inline mentions\n * outside the changed range are preserved and rebased; mentions overlapped\n * by the replacement are removed because their text representation changed.\n */\n setText(next: string): void;\n /**\n * Replace the draft's plain text from the latest committed value. Uses the\n * same structured-state reconciliation as `setText`.\n */\n updateText(updater: (current: string) => string): void;\n /** Clear plain text without clearing independently attached files. */\n clear(): void;\n /**\n * Append text to the draft as a `> ` blockquote block and focus the\n * composer. Blank text is a no-op. This is the \"reference this selection\n * in chat\" primitive.\n */\n addQuote(text: string): void;\n /**\n * Insert an @-mention pill that resolves through this plugin's mention\n * provider at send time — the durable way to reference an entity whose\n * content should be fetched fresh when the message is sent.\n */\n insertMention(mention: PluginComposerMention): void;\n /** Focus the composer caret at the end of the draft. */\n focus(): void;\n}\n/** Current app selection, derived from the route. */\ninterface BbContext {\n projectId: string | null;\n threadId: string | null;\n}\ninterface BbNavigate {\n toThread(threadId: string): void;\n toProject(projectId: string): void;\n /**\n * Navigate to one of this plugin's own nav panels by its `path`.\n * `subPath` targets a location inside the panel (the component's\n * `subPath` prop); `replace` swaps the current history entry instead of\n * pushing — use it for redirects so back does not bounce.\n */\n toPluginPanel(path: string, options?: {\n subPath?: string;\n replace?: boolean;\n }): void;\n /**\n * Navigate to the root compose surface (the new-thread screen). Pass\n * `initialPrompt` to seed the composer draft and `focusPrompt` to focus the\n * composer on arrival — the pairing behind \"Create via chat\" style entry\n * points that drop the user into chat with a prefilled prompt.\n */\n toCompose(options?: {\n initialPrompt?: string;\n focusPrompt?: boolean;\n }): void;\n}\n/**\n * Everything `@bb/plugin-sdk/app` resolves to at runtime. The BB app builds\n * the real implementation and `satisfies` this interface; `bb plugin build`\n * shims the specifier to that object on `globalThis.__bbPluginRuntime`.\n */\ninterface PluginSdkApp {\n definePluginApp(setup: PluginAppSetup): PluginAppDefinition;\n useRpc(): PluginRpcClient;\n useRealtime(channel: string, handler: (payload: unknown) => void): void;\n /**\n * Observe the same shared connection that delivers `useRealtime` signals.\n * Use a subsequent transition to `connected` to reconcile server state that\n * may have changed while ephemeral signals could not be delivered. The first\n * connection can transition from `connecting` and is not a reconnection.\n */\n useRealtimeConnectionState(): PluginRealtimeConnectionState;\n useSettings(): PluginSettingsState;\n useBbContext(): BbContext;\n useBbNavigate(): BbNavigate;\n useComposer(): PluginComposerApi;\n}\n\n/**\n * App-wide server-backed preferences.\n * Client-local settings stay in the frontend localStorage helpers instead.\n */\ndeclare const appSettingsSchema: z$1.ZodObject<{\n caffeinate: z$1.ZodBoolean;\n showKeyboardHints: z$1.ZodBoolean;\n showUnhandledProviderEvents: z$1.ZodBoolean;\n codexMemoryEnabled: z$1.ZodBoolean;\n claudeCodeMemoryEnabled: z$1.ZodBoolean;\n codexSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeWorkflowsDisabled: z$1.ZodBoolean;\n}, z$1.core.$strict>;\ntype AppSettings = z$1.infer;\n\ndeclare const appKeybindingOverridesSchema: z$1.ZodArray;\n shortcut: z$1.ZodNullable>;\n}, z$1.core.$strict>>;\ntype AppKeybindingOverrides = z$1.infer;\n\ndeclare const appThemeSchema: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n}, z$1.core.$strip>;\ntype AppTheme = z$1.infer;\n/**\n * The complete appearance selection a client sends when changing the palette\n * and/or favicon tint. The server validates `themeId` (built-in id or an\n * existing custom theme) and resolves the CSS from disk for custom themes.\n * Callers changing only one facet must carry the other facet forward explicitly.\n */\ndeclare const appThemeSelectionSchema: z$1.ZodObject<{\n themeId: z$1.ZodString;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n}, z$1.core.$strip>;\ntype AppThemeSelection = z$1.infer;\n\ndeclare const changedMessageSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"thread\">;\n id: z$1.ZodOptional;\n metadata: z$1.ZodOptional;\n eventTypes: z$1.ZodOptional>>>>;\n hasPendingInteraction: z$1.ZodOptional;\n projectId: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"project\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"environment\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"host\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"system\">;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>], \"entity\">;\ntype ChangedMessage = z$1.infer;\n\ndeclare const environmentSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodNullable;\n projectId: z$1.ZodString;\n hostId: z$1.ZodString;\n path: z$1.ZodNullable;\n managed: z$1.ZodBoolean;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n branchName: z$1.ZodNullable;\n baseBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n mergeBaseBranch: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n ready: \"ready\";\n retiring: \"retiring\";\n destroying: \"destroying\";\n destroyed: \"destroyed\";\n }>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype Environment = z$1.infer;\n\n/**\n * User-opt-in experiments (the Settings → Experiments toggles). Distinct from\n * `FeatureFlags`: flags are operator-set via env at server start, experiments\n * are user-toggled at runtime and persisted server-side so server-owned\n * policy (e.g. skill injection) can honor them.\n *\n * Every experiment defaults to off — opting in is the point.\n */\ndeclare const experimentsSchema: z$1.ZodObject<{\n claudeCodeMockCliTraffic: z$1.ZodBoolean;\n plugins: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype Experiments = z$1.infer;\n\ndeclare const hostSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n type: z$1.ZodEnum<{\n persistent: \"persistent\";\n }>;\n status: z$1.ZodEnum<{\n connected: \"connected\";\n disconnected: \"disconnected\";\n }>;\n lastSeenAt: z$1.ZodNullable;\n lastRejectedProtocolVersion: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype Host = z$1.infer;\n\ninterface JsonObject {\n [key: string]: JsonValue;\n}\ntype JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;\n\ndeclare const pendingInteractionResolutionSchema: z$1.ZodUnion;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n}, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin_submitted\">;\n}, z$1.core.$strip>]>;\ntype PendingInteractionResolution = z$1.infer;\ndeclare const providerPendingInteractionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n origin: z$1.ZodOptional;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n }, z$1.core.$strip>>;\n payload: z$1.ZodUnion;\n subject: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n itemId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n actions: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"listFiles\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"file_change\">;\n itemId: z$1.ZodString;\n writeScope: z$1.ZodNullable;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>], \"kind\">;\n reason: z$1.ZodNullable;\n availableDecisions: z$1.ZodArray>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>;\n resolution: z$1.ZodNullable;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>>;\n}, z$1.core.$strip>;\ntype ProviderPendingInteraction = z$1.infer;\ndeclare const pluginPendingInteractionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodNullable;\n origin: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n rendererId: z$1.ZodString;\n }, z$1.core.$strip>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n title: z$1.ZodString;\n data: z$1.ZodType>;\n }, z$1.core.$strip>;\n resolution: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginPendingInteraction = z$1.infer;\ntype PendingInteraction = ProviderPendingInteraction | PluginPendingInteraction;\n\ndeclare const projectSourceSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n isDefault: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n type: z$1.ZodLiteral<\"local_path\">;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ProjectSource = z$1.infer;\n\ndeclare const resolvedThreadExecutionOptionsSchema: z$1.ZodObject<{\n seq: z$1.ZodOptional;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n source: z$1.ZodEnum<{\n \"client/thread/start\": \"client/thread/start\";\n \"client/turn/requested\": \"client/turn/requested\";\n \"client/turn/start\": \"client/turn/start\";\n }>;\n}, z$1.core.$strip>;\ntype ResolvedThreadExecutionOptions = z$1.infer;\ndeclare const projectExecutionDefaultsSchema: z$1.ZodObject<{\n providerId: z$1.ZodString;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n}, z$1.core.$strip>;\ntype ProjectExecutionDefaults = z$1.infer;\n\n/** All thread events — provider-originated or system-originated. */\ndeclare const threadEventSchema: z$1.ZodPipe;\n threadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/identity\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/started\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n error: z$1.ZodOptional>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/input/accepted\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n clientRequestId: z$1.ZodString;\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/name/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n threadName: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/compacted\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/goal/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n objective: z$1.ZodString;\n status: z$1.ZodEnum<{\n paused: \"paused\";\n active: \"active\";\n budgetLimited: \"budgetLimited\";\n complete: \"complete\";\n }>;\n tokenBudget: z$1.ZodNullable;\n tokensUsed: z$1.ZodNumber;\n timeUsedSeconds: z$1.ZodNumber;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/goal/cleared\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/started\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"userMessage\">;\n id: z$1.ZodString;\n content: z$1.ZodArray;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n clientRequestId: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"agentMessage\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commandExecution\">;\n id: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n aggregatedOutput: z$1.ZodOptional;\n exitCode: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"fileChange\">;\n id: z$1.ZodString;\n changes: z$1.ZodArray;\n movePath: z$1.ZodOptional;\n diff: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webSearch\">;\n id: z$1.ZodString;\n queries: z$1.ZodArray;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webFetch\">;\n id: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"imageView\">;\n id: z$1.ZodString;\n path: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"toolCall\">;\n id: z$1.ZodString;\n server: z$1.ZodOptional;\n tool: z$1.ZodString;\n arguments: z$1.ZodOptional>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n result: z$1.ZodOptional;\n error: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reasoning\">;\n id: z$1.ZodString;\n summary: z$1.ZodArray;\n content: z$1.ZodArray;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"plan\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"contextCompaction\">;\n id: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"userMessage\">;\n id: z$1.ZodString;\n content: z$1.ZodArray;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n clientRequestId: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"agentMessage\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commandExecution\">;\n id: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n aggregatedOutput: z$1.ZodOptional;\n exitCode: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"fileChange\">;\n id: z$1.ZodString;\n changes: z$1.ZodArray;\n movePath: z$1.ZodOptional;\n diff: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webSearch\">;\n id: z$1.ZodString;\n queries: z$1.ZodArray;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webFetch\">;\n id: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"imageView\">;\n id: z$1.ZodString;\n path: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"toolCall\">;\n id: z$1.ZodString;\n server: z$1.ZodOptional;\n tool: z$1.ZodString;\n arguments: z$1.ZodOptional>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n result: z$1.ZodOptional;\n error: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reasoning\">;\n id: z$1.ZodString;\n summary: z$1.ZodArray;\n content: z$1.ZodArray;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"plan\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"contextCompaction\">;\n id: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/agentMessage/delta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/commandExecution/outputDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n reset: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/fileChange/outputDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/reasoning/summaryTextDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/reasoning/textDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/plan/delta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/mcpToolCall/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n message: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/toolCall/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n message: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/backgroundTask/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/backgroundTask/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/tokenUsage/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n tokenUsage: z$1.ZodObject<{\n total: z$1.ZodObject<{\n totalTokens: z$1.ZodNumber;\n inputTokens: z$1.ZodNumber;\n cachedInputTokens: z$1.ZodNumber;\n outputTokens: z$1.ZodNumber;\n reasoningOutputTokens: z$1.ZodNumber;\n }, z$1.core.$strip>;\n last: z$1.ZodObject<{\n totalTokens: z$1.ZodNumber;\n inputTokens: z$1.ZodNumber;\n cachedInputTokens: z$1.ZodNumber;\n outputTokens: z$1.ZodNumber;\n reasoningOutputTokens: z$1.ZodNumber;\n }, z$1.core.$strip>;\n modelContextWindow: z$1.ZodNullable;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/contextWindowUsage/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n contextWindowUsage: z$1.ZodObject<{\n usedTokens: z$1.ZodNullable;\n modelContextWindow: z$1.ZodNullable;\n estimated: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/plan/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n plan: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n explanation: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/diff/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n diff: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/error\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n message: z$1.ZodString;\n detail: z$1.ZodOptional;\n willRetry: z$1.ZodOptional;\n errorInfo: z$1.ZodOptional;\n providerCode: z$1.ZodNullable;\n httpStatusCode: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/warning\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n category: z$1.ZodEnum<{\n deprecation: \"deprecation\";\n config: \"config\";\n general: \"general\";\n }>;\n summary: z$1.ZodOptional;\n details: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/modelFallback\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n originalModel: z$1.ZodString;\n fallbackModel: z$1.ZodString;\n reason: z$1.ZodEnum<{\n refusal: \"refusal\";\n provider: \"provider\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/unhandled\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerId: z$1.ZodString;\n rawType: z$1.ZodString;\n rawEvent: z$1.ZodObject<{\n jsonrpc: z$1.ZodLiteral<\"2.0\">;\n id: z$1.ZodOptional>;\n method: z$1.ZodString;\n params: z$1.ZodOptional>>;\n }, z$1.core.$strip>;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>], \"type\">, z$1.ZodObject<{\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strip>>, z$1.ZodIntersection;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"client/turn/requested\">;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n requestId: z$1.ZodString;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n senderThreadId: z$1.ZodNullable;\n systemMessageKind: z$1.ZodOptional>;\n systemMessageSubject: z$1.ZodOptional;\n threadId: z$1.ZodString;\n threadName: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-batch\">;\n count: z$1.ZodNumber;\n }, z$1.core.$strip>], \"kind\">>>;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-start\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new-turn\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"auto\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"steer\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>], \"kind\">;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n execution: z$1.ZodObject<{\n seq: z$1.ZodOptional;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n source: z$1.ZodEnum<{\n \"client/thread/start\": \"client/thread/start\";\n \"client/turn/requested\": \"client/turn/requested\";\n \"client/turn/start\": \"client/turn/start\";\n }>;\n permissionMode: z$1.ZodEnum<{\n readonly: \"readonly\";\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n \"workspace-write\": \"workspace-write\";\n }>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"client/turn/start\">;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/error\">;\n threadId: z$1.ZodString;\n code: z$1.ZodOptional;\n message: z$1.ZodString;\n detail: z$1.ZodOptional;\n reconnectAttempt: z$1.ZodOptional;\n reconnectTotal: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/manager/user_message\">;\n threadId: z$1.ZodString;\n text: z$1.ZodString;\n toolCallId: z$1.ZodOptional;\n turnId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/thread/interrupted\">;\n threadId: z$1.ZodString;\n reason: z$1.ZodEnum<{\n \"manual-stop\": \"manual-stop\";\n \"host-daemon-restarted\": \"host-daemon-restarted\";\n \"provider-turn-idle\": \"provider-turn-idle\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/operation\">;\n threadId: z$1.ZodString;\n operation: z$1.ZodString;\n status: z$1.ZodString;\n message: z$1.ZodString;\n operationId: z$1.ZodString;\n metadata: z$1.ZodOptional>>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/permissionGrant/lifecycle\">;\n threadId: z$1.ZodString;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n resolution: z$1.ZodDefault;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">>>;\n statusReason: z$1.ZodDefault>;\n subject: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/userQuestion/lifecycle\">;\n threadId: z$1.ZodString;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n resolution: z$1.ZodDefault;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>>;\n statusReason: z$1.ZodDefault>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/thread-provisioning\">;\n threadId: z$1.ZodString;\n provisioningId: z$1.ZodString;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n active: \"active\";\n cancelled: \"cancelled\";\n }>;\n environmentId: z$1.ZodString;\n entries: z$1.ZodArray;\n key: z$1.ZodString;\n text: z$1.ZodString;\n startedAt: z$1.ZodOptional;\n status: z$1.ZodOptional>;\n metadata: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/provider-turn-watchdog\">;\n threadId: z$1.ZodString;\n reason: z$1.ZodLiteral<\"provider-turn-idle\">;\n thresholdMs: z$1.ZodNumber;\n elapsedMs: z$1.ZodNumber;\n activeTurnId: z$1.ZodString;\n activeTurnStartedAt: z$1.ZodNumber;\n lastActivityEventSequence: z$1.ZodNumber;\n lastActivityEventType: z$1.ZodString;\n lastActivityEventAt: z$1.ZodNumber;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodNullable;\n firedAt: z$1.ZodNumber;\n}, z$1.core.$strip>]>, z$1.ZodObject<{\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strip>>]>>;\ntype ThreadEvent = z$1.infer;\ntype ThreadEventType = ThreadEvent[\"type\"];\n\ndeclare const providerInfoSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n displayName: z$1.ZodString;\n logoUrl: z$1.ZodNullable;\n capabilities: z$1.ZodObject<{\n supportsArchive: z$1.ZodBoolean;\n supportsRename: z$1.ZodBoolean;\n supportsServiceTier: z$1.ZodBoolean;\n supportsUserQuestion: z$1.ZodBoolean;\n supportsFork: z$1.ZodBoolean;\n supportedPermissionModes: z$1.ZodArray>;\n }, z$1.core.$strip>;\n composerActions: z$1.ZodArray;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plan\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"goal\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>], \"kind\">>;\n available: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype ProviderInfo = z$1.infer;\n\ndeclare const threadEventScopeSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n}, z$1.core.$strip>], \"kind\">;\ntype ThreadEventScope = z$1.infer;\n\ntype ThreadEventByType = {\n [TType in ThreadEventType]: Extract;\n};\ntype ThreadEventForType = ThreadEventByType[TType];\ntype StoredThreadEventDataFromEvent = Omit;\ninterface ThreadEventRowBase {\n id: string;\n scope: ThreadEventScope;\n threadId: string;\n seq: number;\n createdAt: number;\n actorHandle: string | null;\n}\ntype ThreadEventRowFromEvent = ThreadEventRowBase & {\n type: TEvent[\"type\"];\n data: StoredThreadEventDataFromEvent;\n};\ntype ThreadEventRowOfType = ThreadEventRowFromEvent>;\ntype ThreadEventRow = {\n [TType in ThreadEventType]: ThreadEventRowOfType;\n}[ThreadEventType];\n\ndeclare const threadStatusSchema: z$1.ZodEnum<{\n error: \"error\";\n active: \"active\";\n starting: \"starting\";\n idle: \"idle\";\n stopping: \"stopping\";\n}>;\ntype ThreadStatus = z$1.infer;\n\ndeclare const threadTimelinePendingTodosSchema: z$1.ZodObject<{\n sourceSeq: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n items: z$1.ZodArray;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ThreadTimelinePendingTodos = z$1.infer;\n\ndeclare const threadQueuedMessageSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n content: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadQueuedMessage = z$1.infer;\n\ndeclare const workspaceFileListResponseSchema: z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype WorkspaceFileListResponse = z$1.infer;\ndeclare const workspacePathListResponseSchema: z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype WorkspacePathListResponse = z$1.infer;\n\ndeclare const createProjectSourceRequestSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodPipe>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"clone\">;\n targetPath: z$1.ZodOptional>>;\n remoteUrl: z$1.ZodOptional;\n}, z$1.core.$strict>], \"type\">;\ntype CreateProjectSourceRequest = z$1.infer;\ndeclare const createProjectRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n source: z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodPipe>;\n }, z$1.core.$strict>;\n}, z$1.core.$strip>;\ntype CreateProjectRequest = z$1.infer;\ndeclare const threadSectionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadSectionResponse = z$1.infer;\ndeclare const createThreadSectionRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype CreateThreadSectionRequest = z$1.infer;\ndeclare const updateThreadSectionRequestSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateThreadSectionRequest = z$1.infer;\ndeclare const deleteThreadSectionRequestSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n}, z$1.core.$strict>;\ntype DeleteThreadSectionRequest = z$1.infer;\ndeclare const threadSectionMutationResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n updatedThreadCount: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadSectionMutationResponse = z$1.infer;\ndeclare const reorderProjectRequestSchema: z$1.ZodObject<{\n previousProjectId: z$1.ZodNullable;\n nextProjectId: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ReorderProjectRequest = z$1.infer;\ndeclare const projectListQuerySchema: z$1.ZodObject<{\n include: z$1.ZodOptional;\n includePersonal: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype ProjectListQuery = z$1.infer;\ndeclare const projectFilesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional>;\n limit: z$1.ZodOptional>;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectFilesQuery = z$1.infer;\ndeclare const projectPathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional>;\n limit: z$1.ZodOptional>;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectPathsQuery = z$1.infer;\ndeclare const projectFileContentQuerySchema: z$1.ZodObject<{\n path: z$1.ZodString;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectFileContentQuery = z$1.infer;\ndeclare const projectBranchesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n hostId: z$1.ZodString;\n selectedBranch: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ProjectBranchesQuery = z$1.infer;\ndeclare const projectBranchesResponseSchema: z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n defaultBranch: z$1.ZodNullable;\n defaultBranchRelation: z$1.ZodNullable>;\n hasUncommittedChanges: z$1.ZodBoolean;\n operation: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"none\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"rebase\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"cherry-pick\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"revert\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>], \"kind\">;\n originDefaultBranch: z$1.ZodNullable;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n defaultWorktreeBaseBranch: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ProjectBranchesResponse = z$1.infer;\ndeclare const promptHistoryQuerySchema: z$1.ZodObject<{\n limit: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PromptHistoryQuery = z$1.infer;\ndeclare const promptHistoryResponseSchema: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>>;\ntype PromptHistoryResponse = z$1.infer;\ndeclare const updateProjectRequestSchema: z$1.ZodObject<{\n name: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype UpdateProjectRequest = z$1.infer;\ndeclare const updateProjectSourceRequestSchema: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodOptional>>;\n isDefault: z$1.ZodOptional>;\n}, z$1.core.$strict>;\ntype UpdateProjectSourceRequest = z$1.infer;\ndeclare const commandListResponseSchema: z$1.ZodObject<{\n commands: z$1.ZodArray;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n description: z$1.ZodNullable;\n argumentHint: z$1.ZodNullable;\n pluginId: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype CommandListResponse = z$1.infer;\n/** Query for the complete command catalog available to a project and provider. */\ndeclare const projectCommandsQuerySchema: z$1.ZodObject<{\n provider: z$1.ZodString;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strict>;\ntype ProjectCommandsQuery = z$1.infer;\ndeclare const projectResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodEnum<{\n personal: \"personal\";\n standard: \"standard\";\n }>;\n name: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n sources: z$1.ZodArray;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ProjectResponse = z$1.infer;\ndeclare const projectWithThreadsResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodEnum<{\n personal: \"personal\";\n standard: \"standard\";\n }>;\n name: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n sources: z$1.ZodArray;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n threads: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>>;\n defaultExecutionOptions: z$1.ZodNullable;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ProjectWithThreadsResponse = z$1.infer;\ndeclare const uploadedPromptAttachmentSchema: z$1.ZodObject<{\n type: z$1.ZodEnum<{\n localImage: \"localImage\";\n localFile: \"localFile\";\n }>;\n path: z$1.ZodString;\n name: z$1.ZodString;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype UploadedPromptAttachment = z$1.infer;\ndeclare const copyProjectAttachmentsRequestSchema: z$1.ZodObject<{\n sourceProjectId: z$1.ZodString;\n paths: z$1.ZodArray;\n}, z$1.core.$strict>;\ntype CopyProjectAttachmentsRequest = z$1.infer;\n\ndeclare const updateEnvironmentRequestSchema: z$1.ZodObject<{\n mergeBaseBranch: z$1.ZodOptional>;\n name: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype UpdateEnvironmentRequest = z$1.infer;\n/**\n * Query for searching paths in an environment's workspace. Unlike the\n * project-scoped variant this needs no `environmentId` — the environment is\n * the route param — and is project-agnostic, so it works for projectless\n * (personal) environments too.\n */\ndeclare const environmentPathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n}, z$1.core.$strip>;\ntype EnvironmentPathsQuery = z$1.infer;\ndeclare const environmentDiffBranchesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n selectedBranch: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype EnvironmentDiffBranchesQuery = z$1.infer;\ndeclare const environmentDiffBranchesResponseSchema: z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype EnvironmentDiffBranchesResponse = z$1.infer;\ndeclare const environmentStatusQuerySchema: z$1.ZodObject<{\n mergeBaseBranch: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype EnvironmentStatusQuery = z$1.infer;\ndeclare const environmentDiffQuerySchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n target: z$1.ZodLiteral<\"uncommitted\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodPipe;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodPipe;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n}, z$1.core.$strip>], \"target\">;\ntype EnvironmentDiffQuery = z$1.infer;\n/**\n * Query for fetching a single file's contents at one side of a diff target.\n * Used by the diff card to reparse the card's patch with full old/new contents\n * so `@pierre/diffs` can render expand-context buttons between hunks.\n *\n * For `branch_committed` / `all`, callers pass the resolved merge-base SHA\n * (`mergeBaseRef`, surfaced by `workspace.diff`) rather than the branch name\n * — the diff itself was computed against that SHA, so reading the old side\n * from the same SHA keeps the file content aligned with the hunk line\n * numbers. Reading from the branch tip is wrong whenever the branch has\n * moved past the merge-base since the file existed there.\n */\ndeclare const environmentDiffFileQuerySchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n target: z$1.ZodLiteral<\"uncommitted\">;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseRef: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"all\">;\n mergeBaseRef: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>], \"target\">;\ntype EnvironmentDiffFileQuery = z$1.infer;\ndeclare const environmentDiffFileResponseSchema: z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n utf8: \"utf8\";\n base64: \"base64\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype EnvironmentDiffFileResponse = z$1.infer;\ndeclare const environmentArchiveThreadsResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n archivedThreadIds: z$1.ZodArray;\n}, z$1.core.$strip>;\ntype EnvironmentArchiveThreadsResponse = z$1.infer;\ndeclare const pullRequestMergeMethodSchema: z$1.ZodEnum<{\n merge: \"merge\";\n squash: \"squash\";\n rebase: \"rebase\";\n}>;\ntype PullRequestMergeMethod = z$1.infer;\ndeclare const commitActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"commit\">;\n message: z$1.ZodString;\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n}, z$1.core.$strip>;\ntype CommitActionResponse = z$1.infer;\ndeclare const squashMergeActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"squash_merge\">;\n merged: z$1.ZodBoolean;\n message: z$1.ZodString;\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SquashMergeActionResponse = z$1.infer;\ndeclare const pullRequestReadyActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_ready\">;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestReadyActionResponse = z$1.infer;\ndeclare const pullRequestMergeActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_merge\">;\n method: z$1.ZodEnum<{\n merge: \"merge\";\n squash: \"squash\";\n rebase: \"rebase\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestMergeActionResponse = z$1.infer;\ndeclare const pullRequestDraftActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_draft\">;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestDraftActionResponse = z$1.infer;\ndeclare const environmentStatusResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n workspace: z$1.ZodObject<{\n workingTree: z$1.ZodObject<{\n insertions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n files: z$1.ZodArray;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n hasUncommittedChanges: z$1.ZodBoolean;\n state: z$1.ZodEnum<{\n clean: \"clean\";\n untracked: \"untracked\";\n dirty_uncommitted: \"dirty_uncommitted\";\n committed_unmerged: \"committed_unmerged\";\n dirty_and_committed_unmerged: \"dirty_and_committed_unmerged\";\n }>;\n }, z$1.core.$strip>;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n branch: z$1.ZodObject<{\n currentBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodString;\n }, z$1.core.$strip>;\n mergeBase: z$1.ZodNullable;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n mergeBaseBranch: z$1.ZodString;\n baseRef: z$1.ZodNullable;\n aheadCount: z$1.ZodNumber;\n behindCount: z$1.ZodNumber;\n hasCommittedUnmergedChanges: z$1.ZodBoolean;\n commits: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\n/**\n * Structured pull-request lookup outcome. \"absent\" is a real answer — the\n * host checked and the branch has no PR (non-git environments resolve to\n * \"absent\" without a daemon call). \"unavailable\" means the lookup itself\n * failed (gh missing, not authenticated, timeout, unreachable workspace), so\n * callers must not render it as \"no PR exists\".\n */\ndeclare const environmentPullRequestResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n pullRequest: z$1.ZodObject<{\n number: z$1.ZodNumber;\n title: z$1.ZodString;\n state: z$1.ZodEnum<{\n merged: \"merged\";\n draft: \"draft\";\n open: \"open\";\n closed: \"closed\";\n }>;\n url: z$1.ZodString;\n baseRefName: z$1.ZodString;\n headRefName: z$1.ZodString;\n updatedAt: z$1.ZodString;\n checks: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n unknown: \"unknown\";\n pending: \"pending\";\n passing: \"passing\";\n failing: \"failing\";\n no_checks: \"no_checks\";\n }>;\n totalCount: z$1.ZodNumber;\n passedCount: z$1.ZodNumber;\n failedCount: z$1.ZodNumber;\n pendingCount: z$1.ZodNumber;\n }, z$1.core.$strict>;\n review: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n none: \"none\";\n approved: \"approved\";\n changes_requested: \"changes_requested\";\n review_required: \"review_required\";\n review_requested: \"review_requested\";\n }>;\n reviewRequestCount: z$1.ZodNumber;\n }, z$1.core.$strict>;\n mergeability: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n unknown: \"unknown\";\n blocked: \"blocked\";\n draft: \"draft\";\n mergeable: \"mergeable\";\n conflicts: \"conflicts\";\n }>;\n mergeStateStatus: z$1.ZodNullable>;\n mergeable: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n attention: z$1.ZodEnum<{\n none: \"none\";\n blocked: \"blocked\";\n merged: \"merged\";\n draft: \"draft\";\n closed: \"closed\";\n changes_requested: \"changes_requested\";\n review_requested: \"review_requested\";\n conflicts: \"conflicts\";\n checks_failed: \"checks_failed\";\n checks_pending: \"checks_pending\";\n ready_to_merge: \"ready_to_merge\";\n }>;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"absent\">;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n message: z$1.ZodString;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentPullRequestResponse = z$1.infer;\ndeclare const environmentDiffResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n diff: z$1.ZodObject<{\n diff: z$1.ZodString;\n truncated: z$1.ZodBoolean;\n shortstat: z$1.ZodString;\n files: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strip>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffResponse = z$1.infer;\ndeclare const environmentDiffFilesResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n files: z$1.ZodArray;\n changeKind: z$1.ZodEnum<{\n deleted: \"deleted\";\n added: \"added\";\n modified: \"modified\";\n renamed: \"renamed\";\n copied: \"copied\";\n type_changed: \"type_changed\";\n }>;\n additions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n binary: z$1.ZodBoolean;\n origin: z$1.ZodEnum<{\n untracked: \"untracked\";\n tracked: \"tracked\";\n }>;\n loadMode: z$1.ZodEnum<{\n auto: \"auto\";\n on_demand: \"on_demand\";\n too_large: \"too_large\";\n }>;\n }, z$1.core.$strip>>;\n shortstat: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n initialPatches: z$1.ZodArray>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n too_many_files: \"too_many_files\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffFilesResponse = z$1.infer;\ndeclare const environmentDiffPatchResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n patches: z$1.ZodArray>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffPatchResponse = z$1.infer;\n/**\n * Body for `POST /diff/patch`: the diff target plus the list of new paths whose\n * patches the client wants. A POST (not GET) because the repeated `paths` array\n * cannot survive flat query parsing. The client supplies only new paths; the\n * server re-derives each file's rename/copy pairing (`previousPath`) from its\n * own TOC.\n */\ndeclare const environmentDiffPatchRequestSchema: z$1.ZodObject<{\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n paths: z$1.ZodArray;\n}, z$1.core.$strict>;\ntype EnvironmentDiffPatchRequest = z$1.infer;\ntype EnvironmentStatusResponse = z$1.infer;\n\ndeclare const providerUsageResponseSchema: z$1.ZodObject<{\n codex: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n claudeCode: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n cursor: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n}, z$1.core.$strip>;\ntype ProviderUsageResponse = z$1.infer;\ntype HostDaemonCommandTransport = \"settled\" | \"onlineRpc\";\ntype HostDaemonCommandEnvironmentLane = \"read\" | \"write\";\ntype HostDaemonFlushEventsBeforeResult = boolean | \"when-initiated\";\ninterface HostDaemonCommandDescriptor {\n type: Type;\n schema: Schema;\n resultSchema: ResultSchema;\n transport: Transport;\n retryable: Retryable;\n flushEventsBeforeResult: HostDaemonFlushEventsBeforeResult;\n envLane: HostDaemonCommandEnvironmentLane | null;\n}\ndeclare const hostDaemonCommandRegistry: {\n \"thread.start\": HostDaemonCommandDescriptor<\"thread.start\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n projectId: z$1.ZodString;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n options: z$1.ZodIntersection;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n claudeCodePermissionMode: z$1.ZodOptional>;\n claudeCodeMockCliTraffic: z$1.ZodOptional>;\n workflowsEnabled: z$1.ZodBoolean;\n memoryEnabled: z$1.ZodOptional;\n providerSubagentsEnabled: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"accept-edits\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"user\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"auto\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"automatic\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"full\">;\n permissionScope: z$1.ZodLiteral<\"full\">;\n approvalReviewer: z$1.ZodNull;\n permissionEscalation: z$1.ZodNull;\n }, z$1.core.$strip>], \"permissionMode\">>;\n instructions: z$1.ZodString;\n dynamicTools: z$1.ZodArray>;\n injectedSkillSources: z$1.ZodArray;\n treeHash: z$1.ZodString;\n entryPath: z$1.ZodString;\n sourceType: z$1.ZodEnum<{\n builtin: \"builtin\";\n \"data-dir\": \"data-dir\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n name: z$1.ZodString;\n description: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-path\">;\n sourceType: z$1.ZodLiteral<\"project\">;\n sourceRootPath: z$1.ZodString;\n skillFilePath: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n disallowedTools: z$1.ZodOptional>;\n instructionMode: z$1.ZodEnum<{\n replace: \"replace\";\n append: \"append\";\n }>;\n type: z$1.ZodLiteral<\"thread.start\">;\n requestId: z$1.ZodString;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n speaker: z$1.ZodOptional>;\n threadStoragePath: z$1.ZodOptional;\n fork: z$1.ZodOptional>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"turn.submit\": HostDaemonCommandDescriptor<\"turn.submit\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"turn.submit\">;\n requestId: z$1.ZodString;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n speaker: z$1.ZodOptional>;\n options: z$1.ZodIntersection;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n claudeCodePermissionMode: z$1.ZodOptional>;\n claudeCodeMockCliTraffic: z$1.ZodOptional>;\n workflowsEnabled: z$1.ZodBoolean;\n memoryEnabled: z$1.ZodOptional;\n providerSubagentsEnabled: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"accept-edits\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"user\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"auto\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"automatic\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"full\">;\n permissionScope: z$1.ZodLiteral<\"full\">;\n approvalReviewer: z$1.ZodNull;\n permissionEscalation: z$1.ZodNull;\n }, z$1.core.$strip>], \"permissionMode\">>;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n resumeContext: z$1.ZodObject<{\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n instructionMode: z$1.ZodEnum<{\n replace: \"replace\";\n append: \"append\";\n }>;\n projectId: z$1.ZodString;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n instructions: z$1.ZodString;\n dynamicTools: z$1.ZodArray>;\n injectedSkillSources: z$1.ZodArray;\n treeHash: z$1.ZodString;\n entryPath: z$1.ZodString;\n sourceType: z$1.ZodEnum<{\n builtin: \"builtin\";\n \"data-dir\": \"data-dir\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n name: z$1.ZodString;\n description: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-path\">;\n sourceType: z$1.ZodLiteral<\"project\">;\n sourceRootPath: z$1.ZodString;\n skillFilePath: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n disallowedTools: z$1.ZodOptional>;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"start\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"auto\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"steer\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>], \"mode\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n appliedAs: z$1.ZodEnum<{\n steer: \"steer\";\n \"new-turn\": \"new-turn\";\n }>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"thread.stop\": HostDaemonCommandDescriptor<\"thread.stop\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.stop\">;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.rename\": HostDaemonCommandDescriptor<\"thread.rename\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.rename\">;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.archive\": HostDaemonCommandDescriptor<\"thread.archive\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"thread.archive\">;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.unarchive\": HostDaemonCommandDescriptor<\"thread.unarchive\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.unarchive\">;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"interactive.resolve\": HostDaemonCommandDescriptor<\"interactive.resolve\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"interactive.resolve\">;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n resolution: z$1.ZodUnion;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin_submitted\">;\n }, z$1.core.$strip>]>;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"codex.inference.complete\": HostDaemonCommandDescriptor<\"codex.inference.complete\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"codex.inference.complete\">;\n model: z$1.ZodString;\n prompt: z$1.ZodString;\n outputSchema: z$1.ZodType>;\n timeoutMs: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n model: z$1.ZodString;\n value: z$1.ZodType>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"codex.voice.transcribe\": HostDaemonCommandDescriptor<\"codex.voice.transcribe\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"codex.voice.transcribe\">;\n model: z$1.ZodString;\n audioBase64: z$1.ZodString;\n mimeType: z$1.ZodString;\n filename: z$1.ZodString;\n prompt: z$1.ZodNullable;\n timeoutMs: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n model: z$1.ZodString;\n text: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"environment.provision\": HostDaemonCommandDescriptor<\"environment.provision\", z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n workspaceProvisionType: z$1.ZodLiteral<\"unmanaged\">;\n path: z$1.ZodString;\n checkout: z$1.ZodOptional;\n name: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new\">;\n name: z$1.ZodString;\n baseBranch: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n sourcePath: z$1.ZodString;\n targetPath: z$1.ZodString;\n branchName: z$1.ZodString;\n baseBranch: z$1.ZodNullable;\n setupTimeoutMs: z$1.ZodNumber;\n workspaceProvisionType: z$1.ZodLiteral<\"managed-worktree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n workspaceProvisionType: z$1.ZodLiteral<\"personal\">;\n targetPath: z$1.ZodString;\n }, z$1.core.$strict>], \"workspaceProvisionType\">, z$1.ZodObject<{\n path: z$1.ZodString;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n branchName: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n transcript: z$1.ZodArray;\n key: z$1.ZodString;\n text: z$1.ZodString;\n startedAt: z$1.ZodOptional;\n status: z$1.ZodOptional>;\n metadata: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"project.clone\": HostDaemonCommandDescriptor<\"project.clone\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.clone\">;\n remoteUrl: z$1.ZodString;\n projectSlug: z$1.ZodString;\n targetPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n }, z$1.core.$strict>, \"settled\", false>;\n \"environment.provision.cancel\": HostDaemonCommandDescriptor<\"environment.provision.cancel\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision.cancel\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n aborted: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"settled\", false>;\n \"environment.destroy\": HostDaemonCommandDescriptor<\"environment.destroy\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"environment.destroy\">;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"workspace.commit\": HostDaemonCommandDescriptor<\"workspace.commit\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.commit\">;\n message: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"workspace.squash_merge\": HostDaemonCommandDescriptor<\"workspace.squash_merge\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.squash_merge\">;\n targetBranch: z$1.ZodString;\n commitMessage: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n merged: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"settled\", false>;\n \"workspace.pull_request_action\": HostDaemonCommandDescriptor<\"workspace.pull_request_action\", z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"ready\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"draft\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"merge\">;\n method: z$1.ZodEnum<{\n merge: \"merge\";\n squash: \"squash\";\n rebase: \"rebase\";\n }>;\n }, z$1.core.$strict>], \"operation\">, z$1.ZodObject<{}, z$1.core.$strict>, \"settled\", false>;\n \"host.list_files\": HostDaemonCommandDescriptor<\"host.list_files\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_files\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n }, z$1.core.$strip>, z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.list_paths\": HostDaemonCommandDescriptor<\"host.list_paths\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_paths\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n includeFiles: z$1.ZodBoolean;\n includeDirectories: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.mkdir\": HostDaemonCommandDescriptor<\"host.mkdir\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.mkdir\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n recursive: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.move_path\": HostDaemonCommandDescriptor<\"host.move_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.move_path\">;\n sourcePath: z$1.ZodString;\n destinationPath: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.remove_path\": HostDaemonCommandDescriptor<\"host.remove_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.remove_path\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n recursive: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.browse_directory\": HostDaemonCommandDescriptor<\"host.browse_directory\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.browse_directory\">;\n path: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n directory: z$1.ZodString;\n parent: z$1.ZodNullable;\n entries: z$1.ZodArray;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.paths_exist\": HostDaemonCommandDescriptor<\"host.paths_exist\", z$1.ZodObject<{\n paths: z$1.ZodPipe, z$1.ZodTransform>;\n type: z$1.ZodLiteral<\"host.paths_exist\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n existence: z$1.ZodRecord;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"project.inspect\": HostDaemonCommandDescriptor<\"project.inspect\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.inspect\">;\n path: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"project.clone_default_path\": HostDaemonCommandDescriptor<\"project.clone_default_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.clone_default_path\">;\n projectSlug: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"host.pick_folder\": HostDaemonCommandDescriptor<\"host.pick_folder\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.pick_folder\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, \"onlineRpc\", false>;\n \"host.caffeinate\": HostDaemonCommandDescriptor<\"host.caffeinate\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.caffeinate\">;\n enabled: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n enabled: z$1.ZodBoolean;\n supported: z$1.ZodBoolean;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"connect-tunnel.ensure-identity\": HostDaemonCommandDescriptor<\"connect-tunnel.ensure-identity\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"connect-tunnel.ensure-identity\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n label: z$1.ZodString;\n baseDomain: z$1.ZodString;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"host.list_commands\": HostDaemonCommandDescriptor<\"host.list_commands\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_commands\">;\n providerId: z$1.ZodString;\n cwd: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commands: z$1.ZodArray;\n origin: z$1.ZodEnum<{\n project: \"project\";\n user: \"user\";\n }>;\n description: z$1.ZodNullable;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.list_branches\": HostDaemonCommandDescriptor<\"host.list_branches\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_branches\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n selectedBranch: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n }, z$1.core.$strip>, z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n defaultBranch: z$1.ZodNullable;\n defaultBranchRelation: z$1.ZodNullable>;\n hasUncommittedChanges: z$1.ZodBoolean;\n operation: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"none\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"rebase\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"cherry-pick\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"revert\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>], \"kind\">;\n originDefaultBranch: z$1.ZodNullable;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.file_metadata\": HostDaemonCommandDescriptor<\"host.file_metadata\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.file_metadata\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n modifiedAtMs: z$1.ZodNumber;\n sizeBytes: z$1.ZodNumber;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.read_file\": HostDaemonCommandDescriptor<\"host.read_file\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.read_file\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n ref: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n modifiedAtMs: z$1.ZodOptional;\n sha256: z$1.ZodString;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.read_file_relative\": HostDaemonCommandDescriptor<\"host.read_file_relative\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.read_file_relative\">;\n rootPath: z$1.ZodString;\n path: z$1.ZodString;\n dotfiles: z$1.ZodEnum<{\n deny: \"deny\";\n allow: \"allow\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n modifiedAtMs: z$1.ZodOptional;\n sha256: z$1.ZodString;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.write_file\": HostDaemonCommandDescriptor<\"host.write_file\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.write_file\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n createParents: z$1.ZodBoolean;\n expectedSha256: z$1.ZodOptional>;\n mode: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"written\">;\n sha256: z$1.ZodString;\n sizeBytes: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"conflict\">;\n currentSha256: z$1.ZodNullable;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", false>;\n \"provider.list_models\": HostDaemonCommandDescriptor<\"provider.list_models\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider.list_models\">;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n models: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n selectedOnlyModels: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"known_acp_agents.status\": HostDaemonCommandDescriptor<\"known_acp_agents.status\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"known_acp_agents.status\">;\n agents: z$1.ZodArray>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n agents: z$1.ZodArray;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"provider.usage\": HostDaemonCommandDescriptor<\"provider.usage\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider.usage\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n codex: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n claudeCode: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n cursor: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"provider_cli.status\": HostDaemonCommandDescriptor<\"provider_cli.status\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider_cli.status\">;\n }, z$1.core.$strict>, z$1.ZodRecord, z$1.ZodObject<{\n displayName: z$1.ZodString;\n executableName: z$1.ZodString;\n executablePath: z$1.ZodNullable;\n installed: z$1.ZodBoolean;\n installSource: z$1.ZodEnum<{\n notInstalled: \"notInstalled\";\n npmGlobal: \"npmGlobal\";\n external: \"external\";\n }>;\n currentVersion: z$1.ZodNullable;\n latestVersion: z$1.ZodNullable;\n minimumSupportedVersion: z$1.ZodNullable;\n npmPackageName: z$1.ZodNullable;\n npmGlobalPackageVersion: z$1.ZodNullable;\n installAction: z$1.ZodNullable;\n label: z$1.ZodEnum<{\n Install: \"Install\";\n Update: \"Update\";\n }>;\n commandKind: z$1.ZodEnum<{\n exec: \"exec\";\n shell: \"shell\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>>;\n needsUpdate: z$1.ZodBoolean;\n versionUnsupported: z$1.ZodBoolean;\n }, z$1.core.$strip>>, \"onlineRpc\", true>;\n \"provider_cli.install\": HostDaemonCommandDescriptor<\"provider_cli.install\", z$1.ZodObject<{\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n actionKind: z$1.ZodEnum<{\n install: \"install\";\n update: \"update\";\n }>;\n type: z$1.ZodLiteral<\"provider_cli.install\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n events: z$1.ZodArray;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"output\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n stream: z$1.ZodEnum<{\n stdout: \"stdout\";\n stderr: \"stderr\";\n }>;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"completed\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n exitCode: z$1.ZodNullable;\n signal: z$1.ZodNullable;\n success: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"error\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"workspace.status\": HostDaemonCommandDescriptor<\"workspace.status\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.status\">;\n mergeBaseBranch: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n workspaceStatus: z$1.ZodObject<{\n workingTree: z$1.ZodObject<{\n insertions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n files: z$1.ZodArray;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n hasUncommittedChanges: z$1.ZodBoolean;\n state: z$1.ZodEnum<{\n clean: \"clean\";\n untracked: \"untracked\";\n dirty_uncommitted: \"dirty_uncommitted\";\n committed_unmerged: \"committed_unmerged\";\n dirty_and_committed_unmerged: \"dirty_and_committed_unmerged\";\n }>;\n }, z$1.core.$strip>;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n branch: z$1.ZodObject<{\n currentBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodString;\n }, z$1.core.$strip>;\n mergeBase: z$1.ZodNullable;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n mergeBaseBranch: z$1.ZodString;\n baseRef: z$1.ZodNullable;\n aheadCount: z$1.ZodNumber;\n behindCount: z$1.ZodNumber;\n hasCommittedUnmergedChanges: z$1.ZodBoolean;\n commits: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diff\": HostDaemonCommandDescriptor<\"workspace.diff\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diff\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n maxDiffBytes: z$1.ZodNumber;\n maxFileListBytes: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n diff: z$1.ZodObject<{\n diff: z$1.ZodString;\n truncated: z$1.ZodBoolean;\n shortstat: z$1.ZodString;\n files: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strip>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diffFiles\": HostDaemonCommandDescriptor<\"workspace.diffFiles\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diffFiles\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n files: z$1.ZodArray;\n statusLetter: z$1.ZodEnum<{\n M: \"M\";\n A: \"A\";\n D: \"D\";\n R: \"R\";\n C: \"C\";\n T: \"T\";\n }>;\n additions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n binary: z$1.ZodBoolean;\n origin: z$1.ZodEnum<{\n untracked: \"untracked\";\n tracked: \"tracked\";\n }>;\n }, z$1.core.$strip>>;\n shortstat: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diffPatch\": HostDaemonCommandDescriptor<\"workspace.diffPatch\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diffPatch\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n paths: z$1.ZodArray;\n maxBytesPerFile: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n patches: z$1.ZodArray>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.pull_request\": HostDaemonCommandDescriptor<\"workspace.pull_request\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request\">;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n pullRequest: z$1.ZodObject<{\n number: z$1.ZodNumber;\n title: z$1.ZodString;\n state: z$1.ZodEnum<{\n OPEN: \"OPEN\";\n CLOSED: \"CLOSED\";\n MERGED: \"MERGED\";\n }>;\n url: z$1.ZodString;\n isDraft: z$1.ZodBoolean;\n baseRefName: z$1.ZodString;\n headRefName: z$1.ZodString;\n updatedAt: z$1.ZodString;\n checks: z$1.ZodArray;\n conclusion: z$1.ZodNullable>;\n url: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n reviewDecision: z$1.ZodNullable>;\n reviewRequestCount: z$1.ZodNumber;\n mergeStateStatus: z$1.ZodNullable>;\n mergeable: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"absent\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n message: z$1.ZodString;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n};\ntype HostDaemonCommandRegistry = typeof hostDaemonCommandRegistry;\ntype AnyHostDaemonCommandDescriptor = HostDaemonCommandRegistry[keyof HostDaemonCommandRegistry];\ntype HostDaemonCommandDescriptorForTransport = Extract;\ntype HostDaemonResultSchemaMapForTransport = {\n [Descriptor in HostDaemonCommandDescriptorForTransport as Descriptor[\"type\"]]: Descriptor[\"resultSchema\"];\n};\ntype HostDaemonOnlineRpcResultSchemaMap = HostDaemonResultSchemaMapForTransport<\"onlineRpc\">;\ntype HostDaemonOnlineRpcResultByType = {\n [K in keyof HostDaemonOnlineRpcResultSchemaMap]: z$1.infer;\n};\n\ndeclare const pickFolderResponseSchema: z$1.ZodObject<{\n path: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype PickFolderResponse = z$1.infer;\ndeclare const pathsExistRequestSchema: z$1.ZodObject<{\n paths: z$1.ZodPipe, z$1.ZodTransform>;\n}, z$1.core.$strip>;\ntype PathsExistRequest = z$1.infer;\ndeclare const pathsExistResponseSchema: z$1.ZodObject<{\n existence: z$1.ZodRecord;\n}, z$1.core.$strip>;\ntype PathsExistResponse = z$1.infer;\ndeclare const providerCliStatusResponseSchema: z$1.ZodRecord, z$1.ZodObject<{\n displayName: z$1.ZodString;\n executableName: z$1.ZodString;\n executablePath: z$1.ZodNullable;\n installed: z$1.ZodBoolean;\n installSource: z$1.ZodEnum<{\n notInstalled: \"notInstalled\";\n npmGlobal: \"npmGlobal\";\n external: \"external\";\n }>;\n currentVersion: z$1.ZodNullable;\n latestVersion: z$1.ZodNullable;\n minimumSupportedVersion: z$1.ZodNullable;\n npmPackageName: z$1.ZodNullable;\n npmGlobalPackageVersion: z$1.ZodNullable;\n installAction: z$1.ZodNullable;\n label: z$1.ZodEnum<{\n Install: \"Install\";\n Update: \"Update\";\n }>;\n commandKind: z$1.ZodEnum<{\n exec: \"exec\";\n shell: \"shell\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>>;\n needsUpdate: z$1.ZodBoolean;\n versionUnsupported: z$1.ZodBoolean;\n}, z$1.core.$strip>>;\ntype ProviderCliStatusResponse = z$1.infer;\ndeclare const providerCliInstallRequestSchema: z$1.ZodObject<{\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n actionKind: z$1.ZodEnum<{\n install: \"install\";\n update: \"update\";\n }>;\n}, z$1.core.$strip>;\ntype ProviderCliInstallRequest = z$1.infer;\ndeclare const providerCliInstallEventSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"started\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n command: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"output\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n stream: z$1.ZodEnum<{\n stdout: \"stdout\";\n stderr: \"stderr\";\n }>;\n text: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"completed\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n exitCode: z$1.ZodNullable;\n signal: z$1.ZodNullable;\n success: z$1.ZodBoolean;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"error\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>], \"type\">;\ntype ProviderCliInstallEvent = z$1.infer;\n\ninterface CreateFilePreviewResponse {\n baseUrl: string;\n expiresAtMs: number;\n}\ntype HostFileReadResponse = HostDaemonOnlineRpcResultByType[\"host.read_file\"];\ntype HostFileWriteResponse = HostDaemonOnlineRpcResultByType[\"host.write_file\"];\ntype HostFileListResponse = HostDaemonOnlineRpcResultByType[\"host.list_files\"];\ntype HostPathListResponse = HostDaemonOnlineRpcResultByType[\"host.list_paths\"];\ntype HostMkdirResponse = HostDaemonOnlineRpcResultByType[\"host.mkdir\"];\ntype HostMovePathResponse = HostDaemonOnlineRpcResultByType[\"host.move_path\"];\ntype HostRemovePathResponse = HostDaemonOnlineRpcResultByType[\"host.remove_path\"];\n\n/**\n * Query for `GET /hosts/:id/directory`, the interactive path browser's\n * single-level directory read. `path` is an absolute directory on the host;\n * omitting it lists the host's home directory (the daemon resolves it, since a\n * remote caller cannot know the host's home).\n */\ndeclare const hostDirectoryQuerySchema: z$1.ZodObject<{\n path: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype HostDirectoryQuery = z$1.infer;\ndeclare const hostDirectoryListingSchema: z$1.ZodObject<{\n directory: z$1.ZodString;\n parent: z$1.ZodNullable;\n entries: z$1.ZodArray;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype HostDirectoryListing = z$1.infer;\n/** Project name is sent so the daemon can derive its host-local checkout path. */\ndeclare const hostCloneDefaultPathQuerySchema: z$1.ZodObject<{\n projectId: z$1.ZodString;\n}, z$1.core.$strip>;\ntype HostCloneDefaultPathQuery = z$1.infer;\ndeclare const hostCloneDefaultPathResponseSchema: z$1.ZodObject<{\n path: z$1.ZodString;\n}, z$1.core.$strict>;\ntype HostCloneDefaultPathResponse = z$1.infer;\ndeclare const createHostJoinCodeResponseSchema: z$1.ZodObject<{\n joinCode: z$1.ZodString;\n hostId: z$1.ZodString;\n expiresAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype CreateHostJoinCodeResponse = z$1.infer;\ndeclare const updateHostRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateHostRequest = z$1.infer;\ntype HostPathsExistRequest = PathsExistRequest;\ntype HostPathsExistResponse = PathsExistResponse;\ndeclare const hostPickFolderRequestSchema: z$1.ZodObject<{\n clientHostId: z$1.ZodString;\n}, z$1.core.$strict>;\ntype HostPickFolderRequest = z$1.infer;\ntype HostPickFolderResponse = PickFolderResponse;\ntype HostProviderCliStatusResponse = ProviderCliStatusResponse;\ntype HostProviderCliInstallRequest = ProviderCliInstallRequest;\ntype HostProviderCliInstallEvent = ProviderCliInstallEvent;\n\ndeclare const pluginUpdateCheckEntrySchema: z$1.ZodObject<{\n id: z$1.ZodString;\n outcome: z$1.ZodEnum<{\n incompatible: \"incompatible\";\n current: \"current\";\n \"update-available\": \"update-available\";\n pinned: \"pinned\";\n unavailable: \"unavailable\";\n }>;\n devMode: z$1.ZodOptional>;\n installed: z$1.ZodObject<{\n version: z$1.ZodString;\n display: z$1.ZodString;\n }, z$1.core.$strip>;\n candidate: z$1.ZodOptional>;\n blocked: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n detail: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PluginUpdateCheckEntry = z$1.infer;\ndeclare const pluginApplyUpdateResultSchema: z$1.ZodObject<{\n applied: z$1.ZodBoolean;\n from: z$1.ZodObject<{\n version: z$1.ZodString;\n display: z$1.ZodString;\n }, z$1.core.$strip>;\n to: z$1.ZodOptional>;\n outcome: z$1.ZodEnum<{\n current: \"current\";\n updated: \"updated\";\n \"rolled-back\": \"rolled-back\";\n }>;\n detail: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PluginApplyUpdateResult$1 = z$1.infer;\ndeclare const pluginSourceDetailSchema: z$1.ZodObject<{\n requested: z$1.ZodString;\n resolved: z$1.ZodString;\n integrity: z$1.ZodOptional;\n registry: z$1.ZodOptional;\n engines: z$1.ZodObject<{\n bb: z$1.ZodOptional;\n bbPluginSdk: z$1.ZodOptional;\n }, z$1.core.$strip>;\n installedAt: z$1.ZodOptional;\n history: z$1.ZodArray>;\n}, z$1.core.$strip>;\ntype PluginSourceDetail = z$1.infer;\ndeclare const installedPluginSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n source: z$1.ZodString;\n rootDir: z$1.ZodString;\n version: z$1.ZodString;\n provenance: z$1.ZodEnum<{\n builtin: \"builtin\";\n direct: \"direct\";\n catalog: \"catalog\";\n }>;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n incompatible: \"incompatible\";\n missing: \"missing\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype InstalledPlugin = z$1.infer;\ndeclare const pluginListResponseSchema: z$1.ZodObject<{\n enabled: z$1.ZodBoolean;\n plugins: z$1.ZodArray;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n incompatible: \"incompatible\";\n missing: \"missing\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginListResponse = z$1.infer;\ndeclare const pluginReloadResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n plugins: z$1.ZodArray;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n incompatible: \"incompatible\";\n missing: \"missing\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginReloadResponse = z$1.infer;\ndeclare const pluginRemoveResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n}, z$1.core.$strip>;\ntype PluginRemoveResponse = z$1.infer;\ndeclare const pluginSettingsResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n schema: z$1.ZodRecord;\n secret: z$1.ZodOptional>;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"boolean\">;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"select\">;\n options: z$1.ZodArray;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project\">;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>], \"type\">>;\n values: z$1.ZodRecord>>;\n}, z$1.core.$strip>;\ntype PluginSettingsResponse = z$1.infer;\ndeclare const pluginTokenResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n token: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PluginTokenResponse = z$1.infer;\ndeclare const pluginCatalogStatusSchema: z$1.ZodObject<{\n pluginCount: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype PluginCatalogStatus = z$1.infer;\ndeclare const pluginCatalogSearchResultSchema: z$1.ZodObject<{\n entryId: z$1.ZodString;\n displayName: z$1.ZodString;\n description: z$1.ZodString;\n icon: z$1.ZodNullable;\n category: z$1.ZodString;\n source: z$1.ZodString;\n installed: z$1.ZodBoolean;\n compatible: z$1.ZodBoolean;\n incompatibleReason: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype PluginCatalogSearchResult$1 = z$1.infer;\n\ndeclare const systemExecutionOptionsResponseSchema: z$1.ZodObject<{\n providers: z$1.ZodArray;\n capabilities: z$1.ZodObject<{\n supportsArchive: z$1.ZodBoolean;\n supportsRename: z$1.ZodBoolean;\n supportsServiceTier: z$1.ZodBoolean;\n supportsUserQuestion: z$1.ZodBoolean;\n supportsFork: z$1.ZodBoolean;\n supportedPermissionModes: z$1.ZodArray>;\n }, z$1.core.$strip>;\n composerActions: z$1.ZodArray;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plan\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"goal\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>], \"kind\">>;\n available: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n models: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n selectedOnlyModels: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n modelLoadError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype SystemExecutionOptionsResponse = z$1.infer;\ndeclare const systemExecutionOptionsQuerySchema: z$1.ZodObject<{\n providerId: z$1.ZodOptional;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SystemExecutionOptionsQuery = z$1.infer;\n/** Omission preserves the existing behavior of reading the primary machine. */\ndeclare const systemUsageLimitsQuerySchema: z$1.ZodObject<{\n hostId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SystemUsageLimitsQuery = z$1.infer;\ndeclare const systemVoiceTranscriptionResponseSchema: z$1.ZodObject<{\n text: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemVoiceTranscriptionResponse = z$1.infer;\ndeclare const systemConfigResponseSchema: z$1.ZodObject<{\n generalSettings: z$1.ZodObject<{\n caffeinate: z$1.ZodBoolean;\n showKeyboardHints: z$1.ZodBoolean;\n showUnhandledProviderEvents: z$1.ZodBoolean;\n codexMemoryEnabled: z$1.ZodBoolean;\n claudeCodeMemoryEnabled: z$1.ZodBoolean;\n codexSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeWorkflowsDisabled: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n keybindings: z$1.ZodArray;\n desktopOnly: z$1.ZodBoolean;\n shortcut: z$1.ZodObject<{\n key: z$1.ZodString;\n mod: z$1.ZodBoolean;\n meta: z$1.ZodBoolean;\n control: z$1.ZodBoolean;\n alt: z$1.ZodBoolean;\n shift: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n when: z$1.ZodObject<{\n all: z$1.ZodArray>;\n none: z$1.ZodArray>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>>;\n defaultKeybindings: z$1.ZodArray;\n desktopOnly: z$1.ZodBoolean;\n shortcut: z$1.ZodObject<{\n key: z$1.ZodString;\n mod: z$1.ZodBoolean;\n meta: z$1.ZodBoolean;\n control: z$1.ZodBoolean;\n alt: z$1.ZodBoolean;\n shift: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n when: z$1.ZodObject<{\n all: z$1.ZodArray>;\n none: z$1.ZodArray>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>>;\n keybindingOverrides: z$1.ZodArray;\n shortcut: z$1.ZodNullable>;\n }, z$1.core.$strict>>;\n experiments: z$1.ZodObject<{\n claudeCodeMockCliTraffic: z$1.ZodBoolean;\n plugins: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n appearance: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n }, z$1.core.$strip>;\n customThemes: z$1.ZodArray;\n pluginThemes: z$1.ZodArray;\n }, z$1.core.$strip>>;\n featureFlags: z$1.ZodObject<{\n placeholder: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n hostDaemonPort: z$1.ZodNullable;\n primaryHostId: z$1.ZodNullable;\n primaryHostPlatform: z$1.ZodNullable>;\n voiceTranscriptionEnabled: z$1.ZodBoolean;\n dataDir: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemConfigResponse = z$1.infer;\ndeclare const systemAttentionResponseSchema: z$1.ZodObject<{\n hasAttention: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype SystemAttentionResponse = z$1.infer;\n/**\n * Theme catalog: the on-disk custom-theme directory plus the discovered custom\n * themes and the active palette. Drives `bb theme list` / `bb theme dir`.\n */\ndeclare const themeCatalogResponseSchema: z$1.ZodObject<{\n dir: z$1.ZodString;\n custom: z$1.ZodArray;\n plugins: z$1.ZodArray;\n }, z$1.core.$strip>>;\n active: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>;\ntype ThemeCatalogResponse = z$1.infer;\ndeclare const systemVersionResponseSchema: z$1.ZodObject<{\n currentVersion: z$1.ZodString;\n latestVersion: z$1.ZodNullable;\n source: z$1.ZodLiteral<\"npm\">;\n updateAvailable: z$1.ZodBoolean;\n isDevelopment: z$1.ZodBoolean;\n upgradeCommand: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemVersionResponse = z$1.infer;\ndeclare const systemConfigReloadResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n}, z$1.core.$strip>;\ntype SystemConfigReloadResponse = z$1.infer;\n\ndeclare const terminalSessionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodNullable;\n environmentId: z$1.ZodNullable;\n hostId: z$1.ZodString;\n title: z$1.ZodString;\n initialCwd: z$1.ZodString;\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n status: z$1.ZodEnum<{\n running: \"running\";\n starting: \"starting\";\n disconnected: \"disconnected\";\n exited: \"exited\";\n }>;\n exitCode: z$1.ZodNullable;\n closeReason: z$1.ZodNullable>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n lastUserInputAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TerminalSession = z$1.infer;\ndeclare const terminalListResponseSchema: z$1.ZodObject<{\n sessions: z$1.ZodArray;\n environmentId: z$1.ZodNullable;\n hostId: z$1.ZodString;\n title: z$1.ZodString;\n initialCwd: z$1.ZodString;\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n status: z$1.ZodEnum<{\n running: \"running\";\n starting: \"starting\";\n disconnected: \"disconnected\";\n exited: \"exited\";\n }>;\n exitCode: z$1.ZodNullable;\n closeReason: z$1.ZodNullable>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n lastUserInputAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype TerminalListResponse = z$1.infer;\ndeclare const createTerminalRequestSchema: z$1.ZodObject<{\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n start: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"command\">;\n command: z$1.ZodString;\n }, z$1.core.$strict>], \"mode\">>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"environment\">;\n environmentId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"host_path\">;\n hostId: z$1.ZodString;\n cwd: z$1.ZodNullable;\n }, z$1.core.$strict>], \"kind\">;\n title: z$1.ZodOptional;\n}, z$1.core.$strict>;\ntype CreateTerminalRequest = z$1.infer;\ndeclare const updateTerminalRequestSchema: z$1.ZodObject<{\n title: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateTerminalRequest = z$1.infer;\ndeclare const terminalInputRequestSchema: z$1.ZodObject<{\n dataBase64: z$1.ZodString;\n}, z$1.core.$strict>;\ntype TerminalInputRequest = z$1.infer;\ndeclare const terminalResizeRequestSchema: z$1.ZodObject<{\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype TerminalResizeRequest = z$1.infer;\ndeclare const terminalOutputQuerySchema: z$1.ZodObject<{\n sinceSeq: z$1.ZodOptional>;\n tailBytes: z$1.ZodOptional>;\n limitChunks: z$1.ZodOptional>;\n}, z$1.core.$strict>;\ntype TerminalOutputQuery = z$1.infer;\ndeclare const terminalOutputResponseSchema: z$1.ZodObject<{\n chunks: z$1.ZodArray>;\n nextSeq: z$1.ZodNumber;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strict>;\ntype TerminalOutputResponse = z$1.infer;\n\ndeclare const timelineRowStatusSchema: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n}>;\ntype TimelineRowStatus = z$1.infer;\ndeclare const timelineRowBaseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype TimelineRowBase = z$1.infer;\ndeclare const timelineConversationRowSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"conversation\">;\n text: z$1.ZodString;\n attachments: z$1.ZodNullable;\n localImagePaths: z$1.ZodArray;\n localFilePaths: z$1.ZodArray;\n }, z$1.core.$strip>>;\n role: z$1.ZodLiteral<\"user\">;\n initiator: z$1.ZodEnum<{\n user: \"user\";\n agent: \"agent\";\n system: \"system\";\n }>;\n senderThreadId: z$1.ZodNullable;\n actorHandle: z$1.ZodDefault>;\n systemMessageKind: z$1.ZodEnum<{\n \"ownership-assigned\": \"ownership-assigned\";\n \"ownership-removed\": \"ownership-removed\";\n \"child-needs-attention\": \"child-needs-attention\";\n \"child-completed\": \"child-completed\";\n \"child-failed\": \"child-failed\";\n \"child-interrupted\": \"child-interrupted\";\n \"child-outcome-batch\": \"child-outcome-batch\";\n unlabeled: \"unlabeled\";\n }>;\n systemMessageSubject: z$1.ZodNullable;\n threadId: z$1.ZodString;\n threadName: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-batch\">;\n count: z$1.ZodNumber;\n }, z$1.core.$strip>], \"kind\">>;\n turnRequest: z$1.ZodObject<{\n kind: z$1.ZodEnum<{\n message: \"message\";\n steer: \"steer\";\n }>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n accepted: \"accepted\";\n }>;\n }, z$1.core.$strip>;\n mentions: z$1.ZodArray, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"conversation\">;\n text: z$1.ZodString;\n attachments: z$1.ZodNullable;\n localImagePaths: z$1.ZodArray;\n localFilePaths: z$1.ZodArray;\n }, z$1.core.$strip>>;\n role: z$1.ZodLiteral<\"assistant\">;\n turnRequest: z$1.ZodNull;\n}, z$1.core.$strip>], \"role\">;\ntype TimelineConversationRow = z$1.infer;\ndeclare const timelineSystemRowSchema: z$1.ZodUnion;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n status: z$1.ZodNullable>;\n systemKind: z$1.ZodEnum<{\n error: \"error\";\n debug: \"debug\";\n reconnect: \"reconnect\";\n }>;\n}, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n status: z$1.ZodNullable>;\n systemKind: z$1.ZodLiteral<\"operation\">;\n operationKind: z$1.ZodEnum<{\n generic: \"generic\";\n compaction: \"compaction\";\n \"thread-provisioning\": \"thread-provisioning\";\n \"thread-interrupted\": \"thread-interrupted\";\n \"provider-unhandled\": \"provider-unhandled\";\n warning: \"warning\";\n deprecation: \"deprecation\";\n }>;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n systemKind: z$1.ZodLiteral<\"operation\">;\n operationKind: z$1.ZodLiteral<\"parent-change\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n parentChange: z$1.ZodObject<{\n action: z$1.ZodEnum<{\n assign: \"assign\";\n release: \"release\";\n transfer: \"transfer\";\n }>;\n previousParentThreadId: z$1.ZodNullable;\n previousParentThreadTitle: z$1.ZodNullable;\n nextParentThreadId: z$1.ZodNullable;\n nextParentThreadTitle: z$1.ZodNullable;\n }, z$1.core.$strip>;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>], \"operationKind\">]>;\ntype TimelineSystemRow = z$1.infer;\ninterface TimelineWorkRowBase extends TimelineRowBase {\n kind: \"work\";\n status: TimelineRowStatus;\n}\ndeclare const timelineCommandWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"command\">;\n callId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n source: z$1.ZodNullable;\n output: z$1.ZodString;\n exitCode: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n activityIntents: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"list_files\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype TimelineCommandWorkRow = z$1.infer;\ndeclare const timelineToolWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"tool\">;\n callId: z$1.ZodString;\n toolName: z$1.ZodString;\n toolArgs: z$1.ZodNullable>>>;\n output: z$1.ZodString;\n completedAt: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n activityIntents: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"list_files\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype TimelineToolWorkRow = z$1.infer;\ndeclare const timelineFileChangeWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"file-change\">;\n callId: z$1.ZodString;\n change: z$1.ZodObject<{\n path: z$1.ZodString;\n kind: z$1.ZodNullable;\n movePath: z$1.ZodNullable;\n diff: z$1.ZodNullable;\n diffStats: z$1.ZodObject<{\n added: z$1.ZodNumber;\n removed: z$1.ZodNumber;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>;\n stdout: z$1.ZodNullable;\n stderr: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n}, z$1.core.$strip>;\ntype TimelineFileChangeWorkRow = z$1.infer;\ndeclare const timelineWebSearchWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"web-search\">;\n callId: z$1.ZodString;\n queries: z$1.ZodArray;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWebSearchWorkRow = z$1.infer;\ndeclare const timelineWebFetchWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"web-fetch\">;\n callId: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWebFetchWorkRow = z$1.infer;\ndeclare const timelineImageViewWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"image-view\">;\n callId: z$1.ZodString;\n path: z$1.ZodString;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineImageViewWorkRow = z$1.infer;\ndeclare const timelineApprovalWorkRowSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"approval\">;\n interactionId: z$1.ZodString;\n target: z$1.ZodObject<{\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n }, z$1.core.$strip>;\n approvalKind: z$1.ZodLiteral<\"file-edit\">;\n lifecycle: z$1.ZodEnum<{\n denied: \"denied\";\n waiting: \"waiting\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"approval\">;\n interactionId: z$1.ZodString;\n target: z$1.ZodObject<{\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n }, z$1.core.$strip>;\n approvalKind: z$1.ZodLiteral<\"permission-grant\">;\n lifecycle: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n denied: \"denied\";\n resolving: \"resolving\";\n granted: \"granted\";\n }>;\n grantScope: z$1.ZodNullable>;\n statusReason: z$1.ZodNullable;\n}, z$1.core.$strip>], \"approvalKind\">;\ntype TimelineApprovalWorkRow = z$1.infer;\ndeclare const timelineQuestionWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"question\">;\n interactionId: z$1.ZodString;\n lifecycle: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n answered: \"answered\";\n }>;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n answers: z$1.ZodNullable;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n statusReason: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineQuestionWorkRow = z$1.infer;\ninterface TimelineDelegationWorkRow extends TimelineWorkRowBase {\n workKind: \"delegation\";\n callId: string;\n toolName: string;\n subagentType: string | null;\n description: string | null;\n output: string;\n completedAt: number | null;\n childRows: TimelineRow[];\n}\n/**\n * A provider background task — a dynamic workflow (Claude Code Workflow tool)\n * or a backgrounded shell command (Bash run_in_background), discriminated by\n * `taskType`. The row outlives its spawning turn: progress and terminal state\n * arrive via thread-scoped events folded into this single row. `workflow` is\n * the merged phase/agent tree, present only for workflows; null for shell\n * commands and for workflows the provider reported no progress records for\n * (degraded rendering falls back to description + summary).\n */\ndeclare const timelineWorkflowWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWorkflowWorkRow = z$1.infer;\ntype TimelineWorkRow = TimelineCommandWorkRow | TimelineToolWorkRow | TimelineFileChangeWorkRow | TimelineWebSearchWorkRow | TimelineWebFetchWorkRow | TimelineImageViewWorkRow | TimelineApprovalWorkRow | TimelineQuestionWorkRow | TimelineDelegationWorkRow | TimelineWorkflowWorkRow;\ninterface TimelineTurnRow extends TimelineRowBase {\n kind: \"turn\";\n turnId: string;\n status: TimelineRowStatus;\n summaryCount: number;\n completedAt: number | null;\n children: TimelineRow[] | null;\n}\ntype TimelineSourceRow = TimelineConversationRow | TimelineWorkRow | TimelineSystemRow;\ntype TimelineRow = TimelineSourceRow | TimelineTurnRow;\n\ndeclare const createThreadRequestSchema: z$1.ZodObject<{\n projectId: z$1.ZodString;\n providerId: z$1.ZodOptional;\n origin: z$1.ZodEnum<{\n plugin: \"plugin\";\n app: \"app\";\n cli: \"cli\";\n sdk: \"sdk\";\n }>;\n originPluginId: z$1.ZodOptional;\n visibility: z$1.ZodOptional>;\n title: z$1.ZodOptional;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n model: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n environment: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reuse\">;\n environmentId: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host\">;\n hostId: z$1.ZodOptional;\n workspace: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unmanaged\">;\n path: z$1.ZodNullable;\n branch: z$1.ZodOptional;\n name: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new\">;\n baseBranch: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"managed-worktree\">;\n baseBranch: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"named\">;\n name: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"default\">;\n }, z$1.core.$strip>], \"kind\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"personal\">;\n }, z$1.core.$strip>], \"type\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project-default\">;\n }, z$1.core.$strip>], \"type\">;\n parentThreadId: z$1.ZodOptional;\n sectionId: z$1.ZodOptional>;\n sourceThreadId: z$1.ZodOptional;\n sourceSeqEnd: z$1.ZodOptional;\n startedOnBehalfOf: z$1.ZodDefault;\n senderThreadId: z$1.ZodString;\n }, z$1.core.$strip>>>;\n originKind: z$1.ZodDefault>>;\n childOrigin: z$1.ZodDefault>>;\n}, z$1.core.$strip>;\ntype CreateThreadRequest = z$1.infer;\ndeclare const sendMessageRequestSchema: z$1.ZodObject<{\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n mode: z$1.ZodEnum<{\n steer: \"steer\";\n start: \"start\";\n auto: \"auto\";\n \"queue-if-active\": \"queue-if-active\";\n \"steer-if-active\": \"steer-if-active\";\n }>;\n senderThreadId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SendMessageRequest = z$1.infer;\ndeclare const createQueuedMessageRequestSchema: z$1.ZodObject<{\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n senderThreadId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype CreateQueuedMessageRequest = z$1.infer;\ndeclare const updateQueuedMessageRequestSchema: z$1.ZodObject<{\n expectedUpdatedAt: z$1.ZodNumber;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype UpdateQueuedMessageRequest = z$1.infer;\ndeclare const sendQueuedMessageRequestSchema: z$1.ZodObject<{\n mode: z$1.ZodEnum<{\n steer: \"steer\";\n auto: \"auto\";\n }>;\n}, z$1.core.$strip>;\ntype SendQueuedMessageRequest = z$1.infer;\ndeclare const reorderQueuedMessageRequestSchema: z$1.ZodObject<{\n previousQueuedMessageId: z$1.ZodNullable;\n nextQueuedMessageId: z$1.ZodNullable;\n groupBoundaryQueuedMessageId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ReorderQueuedMessageRequest = z$1.infer;\ndeclare const setQueuedMessageGroupBoundaryRequestSchema: z$1.ZodObject<{\n expectedGroupedPrefixQueuedMessageIds: z$1.ZodArray;\n groupBoundaryQueuedMessageId: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SetQueuedMessageGroupBoundaryRequest = z$1.infer;\ndeclare const sendQueuedMessageResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n queuedMessage: z$1.ZodObject<{\n id: z$1.ZodString;\n content: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>;\ntype SendQueuedMessageResponse = z$1.infer;\ndeclare const threadListResponseSchema: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n}, z$1.core.$strip>>;\ntype ThreadListResponse = z$1.infer;\ndeclare const threadSearchResponseSchema: z$1.ZodObject<{\n active: z$1.ZodObject<{\n total: z$1.ZodNumber;\n results: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>;\n matches: z$1.ZodArray;\n text: z$1.ZodString;\n highlightRanges: z$1.ZodArray>;\n sourceSeq: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>;\n archived: z$1.ZodObject<{\n total: z$1.ZodNumber;\n results: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>;\n matches: z$1.ZodArray;\n text: z$1.ZodString;\n highlightRanges: z$1.ZodArray>;\n sourceSeq: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>;\ntype ThreadSearchResponse = z$1.infer;\ndeclare const threadResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n environmentId: z$1.ZodNullable;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n canSpawnChild: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype ThreadResponse = z$1.infer;\ndeclare const threadGetQuerySchema: z$1.ZodObject<{\n include: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadGetQuery = z$1.infer;\ndeclare const threadWithIncludesResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n environmentId: z$1.ZodNullable;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n canSpawnChild: z$1.ZodBoolean;\n environment: z$1.ZodOptional;\n projectId: z$1.ZodString;\n hostId: z$1.ZodString;\n path: z$1.ZodNullable;\n managed: z$1.ZodBoolean;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n branchName: z$1.ZodNullable;\n baseBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n mergeBaseBranch: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n ready: \"ready\";\n retiring: \"retiring\";\n destroying: \"destroying\";\n destroyed: \"destroyed\";\n }>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>>>;\n host: z$1.ZodOptional;\n status: z$1.ZodEnum<{\n disconnected: \"disconnected\";\n connected: \"connected\";\n }>;\n lastSeenAt: z$1.ZodNullable;\n lastRejectedProtocolVersion: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>>>;\n}, z$1.core.$strip>;\ntype ThreadWithIncludesResponse = z$1.infer;\ndeclare const threadPendingInteractionsResponseSchema: z$1.ZodArray;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n origin: z$1.ZodOptional;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n }, z$1.core.$strip>>;\n payload: z$1.ZodUnion;\n subject: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n itemId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n actions: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"listFiles\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"file_change\">;\n itemId: z$1.ZodString;\n writeScope: z$1.ZodNullable;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>], \"kind\">;\n reason: z$1.ZodNullable;\n availableDecisions: z$1.ZodArray>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>;\n resolution: z$1.ZodNullable;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodNullable;\n origin: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n rendererId: z$1.ZodString;\n }, z$1.core.$strip>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n title: z$1.ZodString;\n data: z$1.ZodType>;\n }, z$1.core.$strip>;\n resolution: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>]>>;\ntype ThreadPendingInteractionsResponse = z$1.infer;\ndeclare const threadQueuedMessageListResponseSchema: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>>;\ntype ThreadQueuedMessageListResponse = z$1.infer;\ndeclare const threadChildSummaryResponseSchema: z$1.ZodObject<{\n nonDeletedChildCount: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadChildSummaryResponse = z$1.infer;\ndeclare const deleteThreadRequestSchema: z$1.ZodObject<{\n childThreadsConfirmed: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype DeleteThreadRequest = z$1.infer;\ndeclare const updateThreadRequestSchema: z$1.ZodObject<{\n title: z$1.ZodOptional>;\n sectionId: z$1.ZodOptional>;\n parentThreadId: z$1.ZodOptional>;\n model: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype UpdateThreadRequest = z$1.infer;\ndeclare const reorderPinnedThreadRequestSchema: z$1.ZodObject<{\n previousThreadId: z$1.ZodNullable;\n nextThreadId: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ReorderPinnedThreadRequest = z$1.infer;\n/**\n * Requested placement for a thread opened in the app's split layout. Edge\n * placements add panes through the eighth pane; at the cap they replace the\n * focused pane. `replace` always replaces the focused pane.\n */\ndeclare const threadOpenSplitSchema: z$1.ZodEnum<{\n right: \"right\";\n down: \"down\";\n left: \"left\";\n top: \"top\";\n replace: \"replace\";\n}>;\ntype ThreadOpenSplit = z$1.infer;\n/** Optional secondary-panel file to open with a thread. */\ndeclare const threadOpenFileSchema: z$1.ZodObject<{\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n path: z$1.ZodString;\n lineNumber: z$1.ZodNullable;\n}, z$1.core.$strict>;\ntype ThreadOpenFile = z$1.infer;\n/** Response for POST /threads/:id/open: how many connected clients received it. */\ndeclare const threadOpenResponseSchema: z$1.ZodObject<{\n delivered: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadOpenResponse = z$1.infer;\n/** Presentation action for one thread pane in each connected app window. */\ndeclare const threadPaneActionSchema: z$1.ZodEnum<{\n maximize: \"maximize\";\n restore: \"restore\";\n toggle: \"toggle\";\n}>;\ntype ThreadPaneAction = z$1.infer;\n/** Number of connected app clients that received the pane action. */\ndeclare const threadPaneActionResponseSchema: z$1.ZodObject<{\n delivered: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadPaneActionResponse = z$1.infer;\ndeclare const threadArchiveAllResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n archivedThreadIds: z$1.ZodArray;\n}, z$1.core.$strip>;\ntype ThreadArchiveAllResponse = z$1.infer;\ndeclare const threadListQuerySchema: z$1.ZodObject<{\n projectId: z$1.ZodOptional;\n parentThreadId: z$1.ZodOptional;\n sourceThreadId: z$1.ZodOptional;\n archived: z$1.ZodOptional>;\n sectionId: z$1.ZodOptional;\n unsectioned: z$1.ZodOptional>;\n hasParent: z$1.ZodOptional>;\n originKind: z$1.ZodOptional>;\n excludeSideChats: z$1.ZodOptional>;\n childOrigin: z$1.ZodOptional>;\n limit: z$1.ZodOptional;\n offset: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadListQuery = z$1.infer;\ndeclare const threadSearchQuerySchema: z$1.ZodObject<{\n query: z$1.ZodString;\n limitPerGroup: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadSearchQuery = z$1.infer;\ndeclare const threadTimelineQuerySchema: z$1.ZodObject<{\n includeNestedRows: z$1.ZodOptional>;\n segmentLimit: z$1.ZodOptional;\n beforeAnchorSeq: z$1.ZodOptional;\n beforeAnchorId: z$1.ZodOptional;\n summaryOnly: z$1.ZodOptional>;\n afterSequence: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadTimelineQuery = z$1.infer;\ndeclare const timelineTurnSummaryDetailsQuerySchema: z$1.ZodObject<{\n turnId: z$1.ZodString;\n sourceSeqStart: z$1.ZodString;\n sourceSeqEnd: z$1.ZodString;\n}, z$1.core.$strip>;\ntype TimelineTurnSummaryDetailsQuery = z$1.infer;\ndeclare const threadStorageFilesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadStorageFilesQuery = z$1.infer;\ndeclare const threadStoragePathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n}, z$1.core.$strip>;\ntype ThreadStoragePathsQuery = z$1.infer;\ndeclare const timelineTurnSummaryDetailsResponseSchema: z$1.ZodObject<{\n rows: z$1.ZodArray>>;\n}, z$1.core.$strip>;\ntype TimelineTurnSummaryDetailsResponse = z$1.infer;\ndeclare const threadTimelineResponseSchema: z$1.ZodObject<{\n rows: z$1.ZodArray>>;\n activePromptMode: z$1.ZodNullable;\n providerId: z$1.ZodEnum<{\n codex: \"codex\";\n \"claude-code\": \"claude-code\";\n }>;\n prompt: z$1.ZodString;\n }, z$1.core.$strict>>;\n activeThinking: z$1.ZodNullable>;\n activeWorkflow: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n activeBackgroundCommands: z$1.ZodArray;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n pendingTodos: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n goal: z$1.ZodNullable;\n tokenBudget: z$1.ZodNullable;\n tokensUsed: z$1.ZodNumber;\n timeUsedSeconds: z$1.ZodNumber;\n }, z$1.core.$strip>>;\n modelFallback: z$1.ZodNullable;\n message: z$1.ZodString;\n }, z$1.core.$strip>>;\n contextWindowUsage: z$1.ZodOptional>;\n timelinePage: z$1.ZodObject<{\n kind: z$1.ZodEnum<{\n latest: \"latest\";\n older: \"older\";\n }>;\n segmentLimit: z$1.ZodNumber;\n returnedSegmentCount: z$1.ZodNumber;\n hasOlderRows: z$1.ZodBoolean;\n olderCursor: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n maxSeq: z$1.ZodNumber;\n delta: z$1.ZodOptional>>;\n rowOrder: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ThreadTimelineResponse = z$1.infer;\ndeclare const threadConversationOutlineResponseSchema: z$1.ZodObject<{\n items: z$1.ZodArray;\n preview: z$1.ZodString;\n attachmentSummary: z$1.ZodNullable>;\n }, z$1.core.$strict>>;\n maxSeq: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadConversationOutlineResponse = z$1.infer;\ndeclare const threadStorageFileListResponseSchema: z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n storageRootPath: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ThreadStorageFileListResponse = z$1.infer;\ndeclare const threadStoragePathListResponseSchema: z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n storageRootPath: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ThreadStoragePathListResponse = z$1.infer;\n\ndeclare const threadTabsResponseSchema: z$1.ZodObject<{\n revision: z$1.ZodNumber;\n tabs: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"git-diff\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n actionId: z$1.ZodString;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"plugin-panel\">;\n paramsJson: z$1.ZodNullable;\n pluginId: z$1.ZodString;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n projectId: z$1.ZodNullable;\n source: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"working-tree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"head\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge-base\">;\n ref: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">;\n statusLabel: z$1.ZodNullable>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"host-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n isPinned: z$1.ZodBoolean;\n kind: z$1.ZodLiteral<\"thread-storage-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"browser\">;\n title: z$1.ZodNullable;\n url: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"new-tab\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"side-chat\">;\n sourceMessageText: z$1.ZodString;\n sourceSeqEnd: z$1.ZodNullable;\n threadId: z$1.ZodNullable;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"terminal\">;\n terminalId: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n}, z$1.core.$strict>;\ntype ThreadTabsResponse = z$1.infer;\ndeclare const updateThreadTabsRequestSchema: z$1.ZodObject<{\n expectedRevision: z$1.ZodNumber;\n tabs: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"git-diff\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n actionId: z$1.ZodString;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"plugin-panel\">;\n paramsJson: z$1.ZodNullable;\n pluginId: z$1.ZodString;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n projectId: z$1.ZodNullable;\n source: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"working-tree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"head\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge-base\">;\n ref: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">;\n statusLabel: z$1.ZodNullable>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"host-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n isPinned: z$1.ZodBoolean;\n kind: z$1.ZodLiteral<\"thread-storage-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"browser\">;\n title: z$1.ZodNullable;\n url: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"new-tab\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"side-chat\">;\n sourceMessageText: z$1.ZodString;\n sourceSeqEnd: z$1.ZodNullable;\n threadId: z$1.ZodNullable;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"terminal\">;\n terminalId: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n}, z$1.core.$strict>;\ntype UpdateThreadTabsRequest = z$1.infer;\n\ninterface EnvironmentActionArgs {\n environmentId: string;\n}\ninterface EnvironmentGetArgs extends EnvironmentActionArgs {\n signal?: AbortSignal;\n}\ntype EnvironmentMergeBaseBranchUpdateValue = Exclude;\ntype EnvironmentNameUpdateValue = Exclude;\ninterface EnvironmentMergeBaseBranchUpdate {\n mergeBaseBranch: EnvironmentMergeBaseBranchUpdateValue;\n name?: EnvironmentNameUpdateValue;\n}\ninterface EnvironmentNameUpdate {\n mergeBaseBranch?: EnvironmentMergeBaseBranchUpdateValue;\n name: EnvironmentNameUpdateValue;\n}\ntype EnvironmentUpdateFields = EnvironmentMergeBaseBranchUpdate | EnvironmentNameUpdate;\ntype EnvironmentUpdateArgs = EnvironmentUpdateFields & {\n environmentId: string;\n};\ninterface EnvironmentStatusArgs extends EnvironmentStatusQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ntype EnvironmentDiffArgs = EnvironmentDiffQuery & {\n environmentId: string;\n signal?: AbortSignal;\n};\ntype EnvironmentDiffFileArgs = EnvironmentDiffFileQuery & {\n environmentId: string;\n signal?: AbortSignal;\n};\ninterface EnvironmentDiffBranchesArgs extends EnvironmentDiffBranchesQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ninterface EnvironmentCommitArgs {\n environmentId: string;\n}\ninterface EnvironmentSquashMergeArgs {\n environmentId: string;\n mergeBaseBranch: string;\n}\ninterface EnvironmentPullRequestMergeArgs {\n environmentId: string;\n method: PullRequestMergeMethod;\n}\ntype EnvironmentDiffPatchArgs = EnvironmentDiffPatchRequest & {\n environmentId: string;\n signal?: AbortSignal;\n};\ninterface EnvironmentPathsArgs extends EnvironmentPathsQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ntype EnvironmentArchiveThreadsResult = EnvironmentArchiveThreadsResponse;\ntype EnvironmentCommitResult = CommitActionResponse;\ntype EnvironmentDiffResult = EnvironmentDiffResponse;\ntype EnvironmentDiffBranchesResult = EnvironmentDiffBranchesResponse;\ntype EnvironmentDiffFileResult = EnvironmentDiffFileResponse;\ntype EnvironmentDiffFilesResult = EnvironmentDiffFilesResponse;\ntype EnvironmentDiffPatchResult = EnvironmentDiffPatchResponse;\ntype EnvironmentGetResult = Environment;\ntype EnvironmentMarkPullRequestDraftResult = PullRequestDraftActionResponse;\ntype EnvironmentMarkPullRequestReadyResult = PullRequestReadyActionResponse;\ntype EnvironmentMergePullRequestResult = PullRequestMergeActionResponse;\ntype EnvironmentPathsResult = WorkspacePathListResponse;\ntype EnvironmentPullRequestResult = EnvironmentPullRequestResponse;\ntype EnvironmentSquashMergeResult = SquashMergeActionResponse;\ntype EnvironmentStatusResult = EnvironmentStatusResponse;\ntype EnvironmentUpdateResult = Environment;\ninterface EnvironmentsArea {\n archiveThreads(args: EnvironmentActionArgs): Promise;\n commit(args: EnvironmentCommitArgs): Promise;\n diff(args: EnvironmentDiffArgs): Promise;\n diffBranches(args: EnvironmentDiffBranchesArgs): Promise;\n diffFile(args: EnvironmentDiffFileArgs): Promise;\n diffFiles(args: EnvironmentDiffArgs): Promise;\n diffPatch(args: EnvironmentDiffPatchArgs): Promise;\n get(args: EnvironmentGetArgs): Promise;\n pullRequest(args: EnvironmentGetArgs): Promise;\n markPullRequestDraft(args: EnvironmentActionArgs): Promise;\n markPullRequestReady(args: EnvironmentActionArgs): Promise;\n mergePullRequest(args: EnvironmentPullRequestMergeArgs): Promise;\n paths(args: EnvironmentPathsArgs): Promise;\n squashMerge(args: EnvironmentSquashMergeArgs): Promise;\n status(args: EnvironmentStatusArgs): Promise;\n update(args: EnvironmentUpdateArgs): Promise;\n}\n\n/**\n * Host file primitives. `hostId` may be omitted to target the server's\n * primary (local) host. `rootPath`, when set, confines the target beneath\n * that absolute root on the host (symlink-safe).\n */\ninterface FileReadArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n signal?: AbortSignal;\n}\ninterface FileWriteArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n content: string;\n /** Defaults to \"utf8\". */\n contentEncoding?: \"utf8\" | \"base64\";\n /** Defaults to false. */\n createParents?: boolean;\n /**\n * Optimistic-concurrency guard: omitted → unconditional write; a hash →\n * write only when the current content hashes to it (use `read().sha256`);\n * null → create-only. A failed guard resolves to the `conflict` outcome.\n */\n expectedSha256?: string | null;\n /** POSIX permission bits used when creating a file (for example 0o600). */\n mode?: number;\n}\ninterface FileListArgs {\n hostId?: string;\n path: string;\n query?: string;\n limit?: number;\n signal?: AbortSignal;\n}\ninterface PathListArgs extends FileListArgs {\n includeFiles: boolean;\n includeDirectories: boolean;\n}\ninterface FileMkdirArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n recursive?: boolean;\n}\ninterface FileMoveArgs {\n hostId?: string;\n sourcePath: string;\n destinationPath: string;\n rootPath?: string;\n}\ninterface FileRemoveArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n recursive?: boolean;\n}\ninterface FilePreviewArgs {\n hostId?: string;\n rootPath: string;\n signal?: AbortSignal;\n ttlMs?: number;\n}\ntype FileReadResult = HostFileReadResponse;\ntype FileWriteResult = HostFileWriteResponse;\ntype FileListResult = HostFileListResponse;\ntype PathListResult = HostPathListResponse;\ntype FileMkdirResult = HostMkdirResponse;\ntype FileMoveResult = HostMovePathResponse;\ntype FileRemoveResult = HostRemovePathResponse;\ntype FilePreviewResult = CreateFilePreviewResponse;\ninterface FilesArea {\n read(args: FileReadArgs): Promise;\n write(args: FileWriteArgs): Promise;\n list(args: FileListArgs): Promise;\n listPaths(args: PathListArgs): Promise;\n mkdir(args: FileMkdirArgs): Promise;\n move(args: FileMoveArgs): Promise;\n remove(args: FileRemoveArgs): Promise;\n createPreview(args: FilePreviewArgs): Promise;\n}\n\ninterface GuideRenderArgs {\n chapter?: string;\n}\ninterface GuideRenderResult {\n chapter?: string;\n content: string;\n}\ninterface GuideArea {\n render(args?: GuideRenderArgs): GuideRenderResult;\n}\n\ninterface HostGetArgs {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostDeleteArgs {\n hostId: string;\n}\ninterface HostUpdateArgs extends UpdateHostRequest {\n hostId: string;\n}\ninterface HostDirectoryArgs extends HostDirectoryQuery {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostCloneDefaultPathArgs extends HostCloneDefaultPathQuery {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostPathsExistArgs extends HostPathsExistRequest {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostPickFolderArgs extends HostPickFolderRequest {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostProviderCliInstallArgs extends HostProviderCliInstallRequest {\n hostId: string;\n}\ninterface HostListArgs {\n signal?: AbortSignal;\n}\ntype HostCreateJoinCodeResult = CreateHostJoinCodeResponse;\ntype HostDeleteResult = {\n ok: true;\n};\ntype HostDirectoryResult = HostDirectoryListing;\ntype HostGetResult = Host;\ntype HostCloneDefaultPathResult = HostCloneDefaultPathResponse;\ntype HostProviderCliInstallResult = HostProviderCliInstallEvent[];\ntype HostListResult = Host[];\ntype HostPathsExistResult = HostPathsExistResponse;\ntype HostPickFolderResult = HostPickFolderResponse;\ntype HostProviderCliStatusResult = HostProviderCliStatusResponse;\ntype HostUpdateResult = Host;\ninterface HostsArea {\n createJoinCode(): Promise;\n delete(args: HostDeleteArgs): Promise;\n directory(args: HostDirectoryArgs): Promise;\n get(args: HostGetArgs): Promise;\n cloneDefaultPath(args: HostCloneDefaultPathArgs): Promise;\n installProviderCli(args: HostProviderCliInstallArgs): Promise;\n list(args?: HostListArgs): Promise;\n pathsExist(args: HostPathsExistArgs): Promise;\n pickFolder(args: HostPickFolderArgs): Promise;\n providerCliStatus(args: HostGetArgs): Promise;\n update(args: HostUpdateArgs): Promise;\n}\n\ninterface ProjectListArgs {\n include?: ProjectListQuery[\"include\"];\n /** Include the singleton personal project. Defaults to false for compatibility. */\n includePersonal?: boolean;\n signal?: AbortSignal;\n}\ninterface ProjectCreateArgs extends CreateProjectRequest {\n}\ninterface ProjectGetArgs {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectUpdateArgs extends UpdateProjectRequest {\n projectId: string;\n}\ninterface ProjectDeleteArgs {\n projectId: string;\n}\ninterface ProjectReorderArgs extends ReorderProjectRequest {\n projectId: string;\n}\ninterface ProjectPromptHistoryArgs extends PromptHistoryQuery {\n projectId: string;\n signal?: AbortSignal;\n}\n/** Select one project workspace source, or omit both for the primary host. */\ntype ProjectWorkspaceRoutingArgs = {\n environmentId: string;\n hostId?: never;\n} | {\n environmentId?: never;\n hostId: string;\n} | {\n environmentId?: never;\n hostId?: never;\n};\ntype ProjectFilesArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectPathsArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectCommandsArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectFileContentArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ninterface ProjectBranchesArgs extends ProjectBranchesQuery {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectDefaultExecutionOptionsArgs {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectAttachmentFileLike {\n arrayBuffer(): Promise;\n readonly name: string;\n readonly type?: string;\n}\ninterface ProjectAttachmentUploadArgsBase {\n /** MIME override. Omit to use the File/Blob type, when available. */\n mimeType?: string;\n projectId: string;\n}\n/**\n * Upload bytes owned by this SDK client. A bare Blob/byte buffer needs an\n * explicit filename; File-like values can supply their own name.\n */\ntype ProjectAttachmentUploadArgs = ProjectAttachmentUploadArgsBase & ({\n clientFile: ProjectAttachmentFileLike;\n filename?: string;\n} | {\n clientFile: ArrayBuffer | Blob | Uint8Array;\n filename: string;\n});\ninterface ProjectAttachmentReadArgs {\n path: string;\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectAttachmentCopyArgs extends CopyProjectAttachmentsRequest {\n projectId: string;\n}\ntype ProjectSourceAddArgs = CreateProjectSourceRequest & {\n projectId: string;\n};\ninterface ProjectSourceUpdateArgs extends UpdateProjectSourceRequest {\n projectId: string;\n sourceId: string;\n}\ninterface ProjectSourceDeleteArgs {\n projectId: string;\n sourceId: string;\n}\ntype ProjectBranchesResult = ProjectBranchesResponse;\ninterface ProjectAttachmentReadResult {\n bytes: Uint8Array;\n mimeType: string;\n sizeBytes: number;\n}\ntype ProjectAttachmentUploadResult = UploadedPromptAttachment;\ntype ProjectCommandsResult = CommandListResponse;\ntype ProjectCreateResult = ProjectResponse;\ntype ProjectDefaultExecutionOptionsResult = ProjectExecutionDefaults | null;\ntype ProjectDeleteResult = {\n ok: true;\n};\ninterface ProjectFileContentResult {\n /** UTF-8 text or base64, as selected by `contentEncoding`. */\n content: string;\n contentEncoding: \"utf8\" | \"base64\";\n mimeType: string;\n sizeBytes: number;\n}\ntype ProjectFilesResult = WorkspaceFileListResponse;\ntype ProjectGetResult = ProjectResponse;\ntype ProjectListResult = ProjectResponse[] | ProjectWithThreadsResponse[];\ntype ProjectPathsResult = WorkspacePathListResponse;\ntype ProjectPromptHistoryResult = PromptHistoryResponse;\ntype ProjectReorderResult = ProjectResponse[];\ntype ProjectSourceAddResult = ProjectSource;\ntype ProjectSourceDeleteResult = {\n ok: true;\n};\ntype ProjectSourceUpdateResult = ProjectSource;\ntype ProjectUpdateResult = ProjectResponse;\ninterface ProjectSourcesArea {\n add(args: ProjectSourceAddArgs): Promise;\n delete(args: ProjectSourceDeleteArgs): Promise;\n update(args: ProjectSourceUpdateArgs): Promise;\n}\ninterface ProjectAttachmentsArea {\n copy(args: ProjectAttachmentCopyArgs): Promise;\n read(args: ProjectAttachmentReadArgs): Promise;\n upload(args: ProjectAttachmentUploadArgs): Promise;\n}\ninterface ProjectsArea {\n attachments: ProjectAttachmentsArea;\n branches(args: ProjectBranchesArgs): Promise;\n commands(args: ProjectCommandsArgs): Promise;\n create(args: ProjectCreateArgs): Promise;\n defaultExecutionOptions(args: ProjectDefaultExecutionOptionsArgs): Promise;\n delete(args: ProjectDeleteArgs): Promise;\n fileContent(args: ProjectFileContentArgs): Promise;\n files(args: ProjectFilesArgs): Promise;\n get(args: ProjectGetArgs): Promise;\n list(args?: ProjectListArgs): Promise;\n paths(args: ProjectPathsArgs): Promise;\n promptHistory(args: ProjectPromptHistoryArgs): Promise;\n reorder(args: ProjectReorderArgs): Promise;\n sources: ProjectSourcesArea;\n update(args: ProjectUpdateArgs): Promise;\n}\n\n/** Select exactly one provider-discovery host source, or omit both for primary. */\ntype ProviderHostRoutingArgs = {\n environmentId: string;\n hostId?: never;\n} | {\n environmentId?: never;\n hostId: string;\n} | {\n environmentId?: never;\n hostId?: never;\n};\ntype ProviderListArgs = ProviderHostRoutingArgs & {\n signal?: AbortSignal;\n};\ntype ProviderModelsArgs = ProviderHostRoutingArgs & {\n providerId?: string;\n signal?: AbortSignal;\n};\ntype ProviderListResult = ProviderInfo[];\ntype ProviderModelsResult = SystemExecutionOptionsResponse;\ninterface ProvidersArea {\n /** List providers on the environment host, explicit host, or primary host. */\n list(args?: ProviderListArgs): Promise;\n /** List models on the environment host, explicit host, or primary host. */\n models(args?: ProviderModelsArgs): Promise;\n}\n\ninterface PluginIdArgs {\n pluginId: string;\n}\n/** Install directly from a path:, git:, npm:, or builtin: source spec. */\ninterface PluginInstallArgs {\n source: string;\n}\n/** Install an entry from BB's official catalog. */\ninterface PluginCatalogInstallArgs {\n entryId: string;\n}\ninterface PluginReloadArgs {\n pluginId?: string;\n}\ninterface PluginSettingsUpdateArgs extends PluginIdArgs {\n values: Record;\n}\ninterface PluginTokenArgs extends PluginIdArgs {\n rotate?: boolean;\n}\ninterface PluginCheckUpdatesArgs {\n pluginId?: string;\n signal?: AbortSignal;\n}\ninterface PluginRpcArgs extends PluginIdArgs {\n input?: JsonValue;\n method: string;\n outputSchema: z$1.ZodType;\n}\ninterface PluginCatalogSearchArgs {\n query: string;\n signal?: AbortSignal;\n}\ninterface PluginCatalogStatusArgs {\n signal?: AbortSignal;\n}\ninterface PluginGetSettingsArgs extends PluginIdArgs {\n signal?: AbortSignal;\n}\ninterface PluginGetSourceArgs extends PluginIdArgs {\n signal?: AbortSignal;\n}\ninterface PluginListArgs {\n signal?: AbortSignal;\n}\ninterface PluginListUpdateResultsArgs {\n signal?: AbortSignal;\n}\ntype PluginDisableResult = InstalledPlugin;\ntype PluginEnableResult = InstalledPlugin;\ntype PluginGetSettingsResult = PluginSettingsResponse;\ntype PluginInstallResult = InstalledPlugin;\ntype PluginListResult = PluginListResponse;\ntype PluginReloadResult = PluginReloadResponse;\ntype PluginRemoveResult = PluginRemoveResponse;\ntype PluginTokenResult = PluginTokenResponse;\ntype PluginUpdateSettingsResult = PluginSettingsResponse;\ntype PluginGetSourceResult = PluginSourceDetail;\ntype PluginCheckUpdatesResult = PluginUpdateCheckEntry[];\ntype PluginApplyUpdateResult = PluginApplyUpdateResult$1;\ntype PluginCatalogStatusResult = PluginCatalogStatus;\ntype PluginCatalogSearchResult = PluginCatalogSearchResult$1[];\ninterface PluginCatalogArea {\n install(args: PluginCatalogInstallArgs): Promise;\n search(args: PluginCatalogSearchArgs): Promise;\n status(args?: PluginCatalogStatusArgs): Promise;\n}\ninterface PluginsArea {\n applyUpdate(args: PluginIdArgs): Promise;\n callRpc(args: PluginRpcArgs): Promise;\n checkUpdates(args?: PluginCheckUpdatesArgs): Promise;\n catalog: PluginCatalogArea;\n disable(args: PluginIdArgs): Promise;\n enable(args: PluginIdArgs): Promise;\n getSettings(args: PluginGetSettingsArgs): Promise;\n getSource(args: PluginGetSourceArgs): Promise;\n install(args: PluginInstallArgs): Promise;\n list(args?: PluginListArgs): Promise;\n listUpdateResults(args?: PluginListUpdateResultsArgs): Promise;\n reload(args?: PluginReloadArgs): Promise;\n remove(args: PluginIdArgs): Promise;\n token(args: PluginTokenArgs): Promise;\n updateSettings(args: PluginSettingsUpdateArgs): Promise;\n}\n\ntype BbRealtimeUnsubscribe = () => void;\ntype BbRealtimeEventName = \"thread:changed\" | \"project:changed\" | \"environment:changed\" | \"host:changed\" | \"system:changed\" | \"system:config-changed\" | \"realtime:connection\";\ntype ThreadRealtimeEvent = Extract;\ntype ProjectRealtimeEvent = Extract;\ntype EnvironmentRealtimeEvent = Extract;\ntype HostRealtimeEvent = Extract;\ntype SystemRealtimeEvent = Extract;\ntype BbRealtimeConnectionState = \"connecting\" | \"connected\" | \"disconnected\";\ninterface BbRealtimeConnectionEvent {\n reconnectDelayMs: number | null;\n reconnected: boolean;\n state: BbRealtimeConnectionState;\n}\n/**\n * Entity-changed events are delivered as one shared object to every matching\n * listener; their payload types are readonly so a listener cannot mutate what\n * the next listener receives.\n */\ninterface BbRealtimeEventMap {\n \"thread:changed\": ThreadRealtimeEvent;\n \"project:changed\": ProjectRealtimeEvent;\n \"environment:changed\": EnvironmentRealtimeEvent;\n \"host:changed\": HostRealtimeEvent;\n \"system:changed\": SystemRealtimeEvent;\n \"system:config-changed\": SystemRealtimeEvent;\n \"realtime:connection\": BbRealtimeConnectionEvent;\n}\ntype BbRealtimeCallback = (event: BbRealtimeEventMap[TEventName]) => void;\ninterface ThreadRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"thread:changed\">;\n event: \"thread:changed\";\n threadId?: string;\n}\ninterface ProjectRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"project:changed\">;\n event: \"project:changed\";\n projectId?: string;\n}\ninterface EnvironmentRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"environment:changed\">;\n environmentId?: string;\n event: \"environment:changed\";\n}\ninterface HostRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"host:changed\">;\n event: \"host:changed\";\n hostId?: string;\n}\ninterface SystemRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"system:changed\">;\n event: \"system:changed\";\n}\ninterface SystemConfigRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"system:config-changed\">;\n event: \"system:config-changed\";\n}\n/**\n * Connection listeners are pure observers — they never open or hold the\n * socket. A listener registered while a socket already exists receives the\n * latest connection event as a snapshot on the next microtask, so a status\n * UI mounted after connect still learns the current state.\n */\ninterface RealtimeConnectionSubscribeArgs {\n callback: BbRealtimeCallback<\"realtime:connection\">;\n event: \"realtime:connection\";\n}\ntype BbRealtimeSubscribeArgsUnion = ThreadRealtimeSubscribeArgs | ProjectRealtimeSubscribeArgs | EnvironmentRealtimeSubscribeArgs | HostRealtimeSubscribeArgs | SystemRealtimeSubscribeArgs | SystemConfigRealtimeSubscribeArgs | RealtimeConnectionSubscribeArgs;\ntype BbRealtimeSubscribeArgs = Extract;\ninterface BbRealtime {\n subscribe(args: BbRealtimeSubscribeArgs): BbRealtimeUnsubscribe;\n}\n\ninterface StatusGetArgs {\n projectId?: string;\n signal?: AbortSignal;\n threadId?: string;\n}\ninterface StatusThreadSummary {\n environmentId: string | null;\n id: string;\n parentThreadId: string | null;\n pinnedAt: number | null;\n projectId: string;\n status: ThreadStatus;\n title: string | null;\n}\ntype StatusProject = ProjectResponse;\ntype StatusChildThreads = ThreadListResponse;\ninterface StatusResult {\n childThreads: StatusChildThreads | null;\n pendingTodos: ThreadTimelinePendingTodos | null;\n project: StatusProject | null;\n thread: StatusThreadSummary | null;\n}\ninterface StatusArea {\n get(args?: StatusGetArgs): Promise;\n}\n\ntype ThemeGetResult = AppTheme;\ntype ThemeCatalogResult = ThemeCatalogResponse;\ntype ThemeSetInput = AppThemeSelection;\ntype ThemeSetResult = AppTheme;\ninterface ThemeCatalogArgs {\n signal?: AbortSignal;\n}\ninterface ThemeGetArgs {\n signal?: AbortSignal;\n}\ninterface ThemeArea {\n /** The active app palette, resolved server-side (built-in id or custom CSS). */\n get(args?: ThemeGetArgs): Promise;\n /** The custom-theme directory plus discovered themes and the active palette. */\n catalog(args?: ThemeCatalogArgs): Promise;\n /** Set the complete app appearance selection in one request. */\n set(selection: ThemeSetInput): Promise;\n /**\n * Activate a palette by id while preserving the active favicon color. This\n * compatibility shorthand reads the active appearance before writing the\n * complete selection; prefer the object form when both values are known.\n */\n set(themeId: string): Promise;\n}\n\ninterface SystemAttentionArgs {\n signal?: AbortSignal;\n}\ninterface SystemConfigArgs {\n signal?: AbortSignal;\n}\ninterface SystemExecutionOptionsArgs extends SystemExecutionOptionsQuery {\n signal?: AbortSignal;\n}\ninterface SystemUsageLimitsArgs extends SystemUsageLimitsQuery {\n signal?: AbortSignal;\n}\ninterface SystemVersionArgs {\n force?: boolean;\n signal?: AbortSignal;\n}\ninterface SystemVoiceTranscriptionArgs {\n file: Blob;\n prompt?: string;\n signal?: AbortSignal;\n}\ntype SystemAttentionResult = SystemAttentionResponse;\ntype SystemConfigResult = SystemConfigResponse;\ntype SystemExecutionOptionsResult = SystemExecutionOptionsResponse;\ntype SystemReloadConfigResult = SystemConfigReloadResponse;\ntype SystemVoiceTranscriptionResult = SystemVoiceTranscriptionResponse;\ntype SystemUpdateExperimentsResult = Experiments;\ntype SystemUpdateGeneralSettingsResult = AppSettings;\ntype SystemUpdateKeyboardSettingsResult = AppKeybindingOverrides;\ntype SystemUsageLimitsResult = ProviderUsageResponse;\ntype SystemVersionResult = SystemVersionResponse;\ninterface SystemArea {\n attention(args?: SystemAttentionArgs): Promise;\n config(args?: SystemConfigArgs): Promise;\n executionOptions(args?: SystemExecutionOptionsArgs): Promise;\n reloadConfig(): Promise;\n transcribeVoice(args: SystemVoiceTranscriptionArgs): Promise;\n updateExperiments(args: Experiments): Promise;\n updateGeneralSettings(args: AppSettings): Promise;\n updateKeyboardSettings(args: AppKeybindingOverrides): Promise;\n usageLimits(args?: SystemUsageLimitsArgs): Promise;\n version(args?: SystemVersionArgs): Promise;\n}\n\ninterface TerminalThreadScope {\n cwd?: never;\n environmentId?: never;\n hostId?: never;\n kind: \"thread\";\n threadId: string;\n}\ninterface TerminalEnvironmentScope {\n environmentId: string;\n cwd?: never;\n hostId?: never;\n kind: \"environment\";\n threadId?: never;\n}\ninterface TerminalHostPathListScope {\n /** Optional exact initial working-directory filter on the selected host. */\n cwd?: string;\n environmentId?: never;\n hostId: string;\n kind: \"host_path\";\n threadId?: never;\n}\ninterface TerminalHostPathCreateScope {\n /** Null starts in the selected host's home directory. */\n cwd: string | null;\n environmentId?: never;\n hostId: string;\n kind: \"host_path\";\n threadId?: never;\n}\ntype TerminalListScope = TerminalThreadScope | TerminalEnvironmentScope | TerminalHostPathListScope;\ntype TerminalCreateScope = TerminalThreadScope | TerminalEnvironmentScope | TerminalHostPathCreateScope;\ninterface TerminalListArgs {\n signal?: AbortSignal;\n scope: TerminalListScope;\n}\ninterface TerminalCreateArgs {\n cols: number;\n rows: number;\n scope: TerminalCreateScope;\n start?: CreateTerminalRequest[\"start\"];\n title?: string;\n}\ninterface TerminalTargetArgs {\n terminalId: string;\n}\ninterface TerminalGetArgs extends TerminalTargetArgs {\n signal?: AbortSignal;\n}\ninterface TerminalRenameArgs extends TerminalTargetArgs {\n title: UpdateTerminalRequest[\"title\"];\n}\ninterface TerminalCloseArgs extends TerminalTargetArgs {\n mode: \"force\" | \"if-clean\";\n}\ninterface TerminalInputArgs extends TerminalTargetArgs {\n dataBase64: TerminalInputRequest[\"dataBase64\"];\n}\ninterface TerminalResizeArgs extends TerminalTargetArgs {\n cols: TerminalResizeRequest[\"cols\"];\n rows: TerminalResizeRequest[\"rows\"];\n}\ninterface TerminalOutputArgs extends TerminalTargetArgs {\n limitChunks?: TerminalOutputQuery[\"limitChunks\"];\n signal?: AbortSignal;\n sinceSeq?: TerminalOutputQuery[\"sinceSeq\"];\n tailBytes?: TerminalOutputQuery[\"tailBytes\"];\n}\ntype TerminalRestartArgs = TerminalTargetArgs;\ntype TerminalListResult = TerminalListResponse;\ntype TerminalCreateResult = TerminalSession;\ntype TerminalGetResult = TerminalSession;\ntype TerminalRenameResult = TerminalSession;\ntype TerminalCloseResult = TerminalSession;\ntype TerminalInputResult = TerminalSession;\ntype TerminalResizeResult = TerminalSession;\ntype TerminalOutputResult = TerminalOutputResponse;\ntype TerminalRestartResult = TerminalSession;\ninterface TerminalsArea {\n close(args: TerminalCloseArgs): Promise;\n create(args: TerminalCreateArgs): Promise;\n get(args: TerminalGetArgs): Promise;\n input(args: TerminalInputArgs): Promise;\n list(args: TerminalListArgs): Promise;\n output(args: TerminalOutputArgs): Promise;\n rename(args: TerminalRenameArgs): Promise;\n /**\n * Replace a terminal with a shell at the same scope, size, and title.\n * The original command is not replayed because terminal sessions do not\n * persist launch commands. The replacement has a new terminal ID.\n */\n restart(args: TerminalRestartArgs): Promise;\n resize(args: TerminalResizeArgs): Promise;\n}\n\ninterface ThreadListArgs {\n archived?: boolean;\n excludeSideChats?: boolean;\n sectionId?: string;\n hasParent?: boolean;\n limit?: number;\n offset?: number;\n originKind?: ThreadListQuery[\"originKind\"];\n parentThreadId?: string;\n projectId?: string;\n signal?: AbortSignal;\n sourceThreadId?: string;\n unsectioned?: boolean;\n}\ninterface ThreadSearchArgs extends ThreadSearchQuery {\n signal?: AbortSignal;\n}\ninterface ThreadGetArgs {\n include?: ThreadGetQuery[\"include\"];\n signal?: AbortSignal;\n threadId: string;\n}\ntype ThreadGetResult = ThreadResponse | ThreadWithIncludesResponse;\ntype ThreadListResult = ThreadListResponse;\ntype ThreadSearchResult = ThreadSearchResponse;\ninterface ThreadOutputResponse {\n output: string | null;\n}\ntype ThreadMutationResult = ThreadResponse;\ntype ThreadSpawnResult = ThreadResponse;\ntype ThreadInteractionGetResult = PendingInteraction;\ntype ThreadInteractionListResult = ThreadPendingInteractionsResponse;\ntype ThreadInteractionResolveResult = PendingInteraction;\ntype ThreadInteractionRespondResult = PendingInteraction;\ntype ThreadInteractionCancelResult = PendingInteraction;\ntype ThreadEventsListResult = ThreadEventRow[];\ntype ThreadEventWaitResult = ThreadEventRow | null;\ntype ThreadTimelineResult = ThreadTimelineResponse;\ntype ThreadArchiveResult = ThreadArchiveAllResponse;\ntype ThreadOpenResult = ThreadOpenResponse;\ntype ThreadPaneActionResult = ThreadPaneActionResponse;\ntype ThreadDeleteResult = {\n ok: true;\n};\ntype ThreadSendResult = {\n ok: true;\n};\ntype ThreadStopResult = {\n ok: true;\n};\ntype ThreadUnarchiveResult = {\n ok: true;\n};\ntype ThreadArchiveAllResult = ThreadArchiveAllResponse;\ntype ThreadReadStateResult = ThreadResponse;\ntype ThreadPinOrderResult = ThreadListResponse;\ntype ThreadPromptHistoryResult = PromptHistoryResponse;\ntype ThreadQueuedMessagesResult = ThreadQueuedMessageListResponse;\ntype ThreadQueuedMessageCreateResult = ThreadQueuedMessage;\ntype ThreadQueuedMessageUpdateResult = ThreadQueuedMessage;\ntype ThreadQueuedMessageDeleteResult = {\n ok: true;\n};\ntype ThreadQueuedMessageReorderResult = ThreadQueuedMessageListResponse;\ntype ThreadQueuedMessageSendResult = SendQueuedMessageResponse;\ntype ThreadQueuedMessageGroupBoundaryResult = ThreadQueuedMessageListResponse;\ntype ThreadTabsResult = ThreadTabsResponse;\ntype ThreadTabsUpdateResult = ThreadTabsResponse;\ntype ThreadStorageFilesResult = ThreadStorageFileListResponse;\ntype ThreadStoragePathsResult = ThreadStoragePathListResponse;\ntype ThreadChildSummaryResult = ThreadChildSummaryResponse;\ntype ThreadDefaultExecutionOptionsResult = ResolvedThreadExecutionOptions | null;\ntype ThreadConversationOutlineResult = ThreadConversationOutlineResponse;\ntype ThreadTimelineTurnSummaryDetailsResult = TimelineTurnSummaryDetailsResponse;\ninterface ThreadSpawnBaseArgs extends Omit {\n childOrigin?: CreateThreadRequest[\"childOrigin\"];\n origin?: CreateThreadRequest[\"origin\"];\n originKind?: CreateThreadRequest[\"originKind\"];\n startedOnBehalfOf?: CreateThreadRequest[\"startedOnBehalfOf\"];\n}\ntype ThreadSpawnArgs = ThreadSpawnBaseArgs & ({\n input: CreateThreadRequest[\"input\"];\n prompt?: never;\n} | {\n input?: never;\n prompt: string;\n});\ninterface ThreadUpdateArgs extends UpdateThreadRequest {\n threadId: string;\n}\ninterface ThreadDeleteArgs extends DeleteThreadRequest {\n threadId: string;\n}\ninterface ThreadSendArgs extends SendMessageRequest {\n threadId: string;\n}\ninterface ThreadActionArgs {\n threadId: string;\n}\ninterface ThreadStatusArgs extends ThreadActionArgs {\n signal?: AbortSignal;\n}\ninterface ThreadPromptHistoryArgs extends PromptHistoryQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadPinOrderArgs extends ReorderPinnedThreadRequest {\n threadId: string;\n}\ninterface ThreadQueuedMessageArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadQueuedMessageCreateArgs extends CreateQueuedMessageRequest {\n threadId: string;\n}\ninterface ThreadQueuedMessageUpdateArgs extends ThreadQueuedMessageTargetArgs, UpdateQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageTargetArgs {\n queuedMessageId: string;\n threadId: string;\n}\ninterface ThreadQueuedMessageSendArgs extends ThreadQueuedMessageTargetArgs, SendQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageReorderArgs extends ThreadQueuedMessageTargetArgs, ReorderQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageGroupBoundaryArgs extends SetQueuedMessageGroupBoundaryRequest {\n threadId: string;\n}\ninterface ThreadStorageFilesArgs extends ThreadStorageFilesQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadStoragePathsArgs extends ThreadStoragePathsQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadTimelineTurnSummaryDetailsArgs extends TimelineTurnSummaryDetailsQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadTabsUpdateArgs extends UpdateThreadTabsRequest {\n threadId: string;\n}\ninterface ThreadOpenArgs {\n threadId: string;\n split?: ThreadOpenSplit;\n file: ThreadOpenFile | null;\n}\ninterface ThreadPaneActionArgs {\n action: ThreadPaneAction;\n threadId: string;\n}\ninterface ThreadEventsListArgs {\n afterSeq?: string;\n limit?: string;\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadEventWaitArgs {\n afterSeq?: string;\n signal?: AbortSignal;\n threadId: string;\n type: string;\n waitMs: string;\n}\ninterface ThreadTimelineArgs extends ThreadTimelineQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadOutputArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadInteractionListArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadInteractionTargetArgs {\n interactionId: string;\n threadId: string;\n}\ninterface ThreadInteractionGetArgs extends ThreadInteractionTargetArgs {\n signal?: AbortSignal;\n}\ninterface ThreadInteractionResolveArgs extends ThreadInteractionTargetArgs {\n resolution: PendingInteractionResolution;\n}\ninterface ThreadInteractionRespondArgs extends ThreadInteractionTargetArgs {\n value: JsonValue;\n}\ntype ThreadWaitTarget = {\n kind: \"status\";\n status: ThreadStatus;\n} | {\n kind: \"event\";\n eventType: string;\n};\ninterface ThreadWaitArgs {\n event?: string;\n pollIntervalMs?: number;\n signal?: AbortSignal;\n status?: ThreadStatus;\n threadId: string;\n timeoutMs?: number;\n}\ntype ThreadWaitResult = {\n event: NonNullable;\n matched: true;\n target: Extract;\n threadId: string;\n} | {\n matched: true;\n target: Extract;\n thread: ThreadGetResult;\n threadId: string;\n};\ninterface ThreadInteractionsArea {\n cancel(args: ThreadInteractionTargetArgs): Promise;\n get(args: ThreadInteractionGetArgs): Promise;\n list(args: ThreadInteractionListArgs): Promise;\n resolve(args: ThreadInteractionResolveArgs): Promise;\n respond(args: ThreadInteractionRespondArgs): Promise;\n}\ninterface ThreadEventsArea {\n list(args: ThreadEventsListArgs): Promise;\n wait(args: ThreadEventWaitArgs): Promise;\n}\ninterface ThreadQueuedMessagesArea {\n create(args: ThreadQueuedMessageCreateArgs): Promise;\n delete(args: ThreadQueuedMessageTargetArgs): Promise;\n list(args: ThreadQueuedMessageArgs): Promise;\n reorder(args: ThreadQueuedMessageReorderArgs): Promise;\n send(args: ThreadQueuedMessageSendArgs): Promise;\n setGroupBoundary(args: ThreadQueuedMessageGroupBoundaryArgs): Promise;\n update(args: ThreadQueuedMessageUpdateArgs): Promise;\n}\ninterface ThreadTabsArea {\n get(args: ThreadStatusArgs): Promise;\n update(args: ThreadTabsUpdateArgs): Promise;\n}\ninterface ThreadsArea {\n archive(args: ThreadActionArgs): Promise;\n archiveAll(args: ThreadActionArgs): Promise;\n childSummary(args: ThreadStatusArgs): Promise;\n conversationOutline(args: ThreadStatusArgs): Promise;\n defaultExecutionOptions(args: ThreadStatusArgs): Promise;\n delete(args: ThreadDeleteArgs): Promise;\n events: ThreadEventsArea;\n get(args: ThreadGetArgs): Promise;\n interactions: ThreadInteractionsArea;\n list(args?: ThreadListArgs): Promise;\n markRead(args: ThreadActionArgs): Promise;\n markUnread(args: ThreadActionArgs): Promise;\n open(args: ThreadOpenArgs): Promise;\n paneAction(args: ThreadPaneActionArgs): Promise;\n output(args: ThreadOutputArgs): Promise;\n pin(args: ThreadActionArgs): Promise;\n promptHistory(args: ThreadPromptHistoryArgs): Promise;\n queuedMessages: ThreadQueuedMessagesArea;\n reorderPinned(args: ThreadPinOrderArgs): Promise;\n search(args: ThreadSearchArgs): Promise;\n send(args: ThreadSendArgs): Promise;\n spawn(args: ThreadSpawnArgs): Promise;\n stop(args: ThreadActionArgs): Promise;\n tabs: ThreadTabsArea;\n timeline(args: ThreadTimelineArgs): Promise;\n timelineTurnSummaryDetails(args: ThreadTimelineTurnSummaryDetailsArgs): Promise;\n storageFiles(args: ThreadStorageFilesArgs): Promise;\n storagePaths(args: ThreadStoragePathsArgs): Promise;\n unarchive(args: ThreadActionArgs): Promise;\n unpin(args: ThreadActionArgs): Promise;\n update(args: ThreadUpdateArgs): Promise;\n wait(args: ThreadWaitArgs): Promise;\n}\n\ntype ThreadSectionCreateResult = ThreadSectionResponse;\ntype ThreadSectionUpdateResult = ThreadSectionMutationResponse;\ntype ThreadSectionDeleteResult = ThreadSectionMutationResponse;\ntype ThreadSectionListResult = ThreadSectionResponse[];\ninterface ThreadSectionListArgs {\n signal?: AbortSignal;\n}\ninterface ThreadSectionsArea {\n create(args: CreateThreadSectionRequest): Promise;\n delete(args: DeleteThreadSectionRequest): Promise;\n list(args?: ThreadSectionListArgs): Promise;\n update(args: UpdateThreadSectionRequest): Promise;\n}\n\ninterface BbSdk extends BbRealtime {\n environments: EnvironmentsArea;\n files: FilesArea;\n guide: GuideArea;\n hosts: HostsArea;\n projects: ProjectsArea;\n plugins: PluginsArea;\n providers: ProvidersArea;\n status: StatusArea;\n system: SystemArea;\n terminals: TerminalsArea;\n theme: ThemeArea;\n threadSections: ThreadSectionsArea;\n threads: ThreadsArea;\n}\n\n/**\n * The backend plugin API contract — the `bb` object handed to a plugin's\n * `server.ts` factory (`export default function plugin(bb: BbPluginApi)`).\n *\n * Types only: the implementation lives in the BB server\n * (apps/server/src/services/plugins/plugin-api.ts), which imports these\n * shapes so the contract and the implementation cannot drift. Plugin authors\n * import them type-only (`import type { BbPluginApi } from\n * \"@bb/plugin-sdk\"`); the import is erased when BB loads the file.\n *\n * Runtime classes stay host-side. NeedsConfigurationError in particular is\n * matched by NAME, so plugin code needs no runtime import:\n * `throw Object.assign(new Error(msg), { name: \"NeedsConfigurationError\" })`.\n */\ninterface PluginLogger {\n debug(message: string): void;\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n/**\n * Declarative settings descriptors (`bb.settings.define`). Deliberately plain\n * data — not zod — so the host can render settings forms and the CLI can\n * parse values without executing plugin code.\n */\ntype PluginSettingDescriptor = {\n type: \"string\";\n label: string;\n description?: string;\n /** Stored in a 0600 file under /plugins//secrets/, never in the db or sent to the frontend. */\n secret?: true;\n default?: string;\n} | {\n type: \"boolean\";\n label: string;\n description?: string;\n default?: boolean;\n} | {\n type: \"select\";\n label: string;\n description?: string;\n options: string[];\n default?: string;\n} | {\n type: \"project\";\n label: string;\n description?: string;\n default?: string;\n};\ntype PluginSettingDescriptors = Record;\ntype PluginSettingValue = string | boolean;\n/** `default` present → non-optional value; absent → `T | undefined`. */\ntype PluginSettingsValues> = {\n [K in keyof Ds]: Ds[K] extends {\n default: string | boolean;\n } ? PluginSettingValueOf : PluginSettingValueOf | undefined;\n};\ntype PluginSettingValueOf = D extends {\n type: \"boolean\";\n} ? boolean : string;\ninterface PluginSettingsHandle> {\n /** Load-safe: callable inside the factory. */\n get(): Promise>;\n /** Fires after values change through the settings route/CLI. */\n onChange(listener: (next: PluginSettingsValues, prev: PluginSettingsValues) => void): void;\n}\ninterface PluginSettings {\n define>(descriptors: Ds): PluginSettingsHandle;\n}\ninterface PluginKvStorage {\n get(key: string): Promise;\n set(key: string, value: unknown): Promise;\n delete(key: string): Promise;\n list(prefix?: string): Promise;\n}\ninterface PluginStorage {\n /** Namespaced JSON key-value rows in bb.db; values ≤256KB each. */\n kv: PluginKvStorage;\n /**\n * Open (or reuse the path of) the plugin's own SQLite database at\n * /plugins//data.db — the server's better-sqlite3, WAL mode,\n * busy_timeout 5000. Handles are host-tracked and closed on\n * dispose/reload; a closed handle throws on use.\n */\n database(): Database.Database;\n /**\n * Ordered-statement migration helper: statement index = migration id in a\n * `_bb_migrations` table; unapplied statements run in one transaction.\n * Append-only — never reorder or edit shipped statements.\n */\n migrate(db: Database.Database, statements: string[]): void;\n}\n/**\n * Thread lifecycle events a plugin can observe (design §4.5). Observe-only:\n * handlers run fire-and-forget after the transition is applied and can never\n * block or veto it. `thread` is the same public DTO GET /threads/:id serves.\n */\ninterface PluginThreadEventPayloads {\n /** Fired after a thread row is created. */\n \"thread.created\": {\n thread: ThreadResponse;\n };\n /** Fired when a thread transitions into `active`. */\n \"thread.active\": {\n thread: ThreadResponse;\n };\n /** Fired when a thread transitions into `idle`. `lastAssistantText` is\n * assembled the same way GET /threads/:id/output is. */\n \"thread.idle\": {\n thread: ThreadResponse;\n lastAssistantText: string | null;\n };\n /** Fired when a thread transitions into `error`. `error` is the latest\n * system/error event message, when one exists. */\n \"thread.failed\": {\n thread: ThreadResponse;\n error: string | null;\n };\n /** Fired after a thread is soft-deleted. */\n \"thread.deleted\": {\n thread: ThreadResponse;\n };\n}\ntype PluginThreadEventName = keyof PluginThreadEventPayloads;\ntype PluginThreadEventHandler = (payload: PluginThreadEventPayloads[E]) => void | Promise;\ntype PluginHttpAuthMode = \"local\" | \"token\" | \"none\";\ntype PluginHttpHandler = (context: Context) => Response | Promise;\ninterface PluginHttp {\n /**\n * Register an HTTP route, mounted at\n * `/api/v1/plugins//http/`. Auth modes (default \"local\"):\n * - \"local\": Origin/Host must be a local BB app origin; non-GET requires\n * content-type application/json (forces a CORS preflight).\n * - \"token\": requires the per-plugin token (`bb plugin token `) via\n * the x-bb-plugin-token header or ?token=.\n * - \"none\": no checks — only for signature-verified webhooks.\n */\n route(method: string, path: string, handler: PluginHttpHandler, opts?: {\n auth?: PluginHttpAuthMode;\n }): void;\n}\ninterface PluginRpc {\n /**\n * Register a Standard Schema-driven rpc contract and its inferred handlers,\n * served at POST\n * `/api/v1/plugins//rpc/` with \"local\" auth semantics. The\n * host validates input before invocation and output before strict JSON\n * serialization. The response is `{ ok: true, result }` or\n * `{ ok: false, error: { code, message, issues? } }`.\n */\n register(contract: Contract, handlers: PluginRpcHandlers): void;\n}\ninterface PluginRealtime {\n /**\n * Broadcast an ephemeral `plugin-signal` WS message\n * `{ pluginId, channel, payload }` to every connected client (V1 has no\n * per-channel subscriptions). `payload` must be JSON-serializable;\n * `undefined` is normalized to `null`. Nothing is persisted.\n */\n publish(channel: string, payload: unknown): void;\n}\ninterface PluginBackground {\n /**\n * Register a long-lived background service. `start` runs after the\n * factory completes and should resolve when `signal` aborts\n * (dispose/reload/disable/shutdown). A crash restarts it with capped\n * exponential backoff; throwing NeedsConfigurationError marks the plugin\n * `needs-configuration` and stops restarting until the next load.\n */\n service(name: string, service: {\n start(signal: AbortSignal): void | Promise;\n }): void;\n /**\n * Register a cron schedule (5-field expression, server-local time). The\n * durable row keyed (pluginId, name) is upserted at load; the periodic\n * sweep claims due rows with a CAS on next_run_at, but only while this\n * plugin is loaded. Failures land in last_status/last_error, visible in\n * `bb plugin list`.\n */\n schedule(name: string, cron: string, fn: () => void | Promise): void;\n}\ninterface PluginCliCommandInfo {\n name: string;\n summary: string;\n usage: string;\n}\n/** Context forwarded from the invoking CLI when known; all fields optional. */\ninterface PluginCliContext {\n cwd?: string;\n threadId?: string;\n projectId?: string;\n /** Aborted when the invoking CLI HTTP request disconnects. */\n signal?: AbortSignal;\n}\ntype PluginInteractionCancelReason = \"user\" | \"request-aborted\" | \"thread-stopped\" | \"thread-deleted\" | \"plugin-disposed\" | \"server-restarted\" | \"timeout\";\ntype PluginInteractionResult = {\n outcome: \"submitted\";\n value: JsonValue$1;\n} | {\n outcome: \"cancelled\";\n reason: PluginInteractionCancelReason;\n};\ninterface PluginInteractionRequest {\n threadId: string;\n rendererId: string;\n title: string;\n payload: JsonValue$1;\n /** Defaults to ten minutes; capped at one hour. */\n timeoutMs?: number;\n}\ninterface PluginCliResult {\n exitCode: number;\n stdout?: string;\n stderr?: string;\n}\n/**\n * Maximum combined UTF-8 bytes accepted from plugin CLI stdout and stderr.\n * This is the shared source of truth for production and the testing harness.\n */\ndeclare const PLUGIN_CLI_OUTPUT_MAX_BYTES: number;\ninterface PluginCliOutputLimitError {\n code: \"plugin_cli_output_too_large\";\n message: string;\n maxBytes: number;\n stdoutBytes: number;\n stderrBytes: number;\n totalBytes: number;\n}\n/** Normalized host result returned by the plugin CLI HTTP/testing boundary. */\ninterface PluginCliExecutionResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n error?: PluginCliOutputLimitError;\n}\ninterface PluginCliRegistration {\n /** Top-level command name (`bb …`): lowercase [a-z0-9-]+, and not\n * a core bb command (see RESERVED_BB_CLI_COMMANDS in the server). */\n name: string;\n summary: string;\n /** Subcommand metadata rendered in help and the plugin-commands skill\n * without executing plugin code. Parsing argv is plugin-owned. */\n commands?: PluginCliCommandInfo[];\n run(argv: string[], ctx: PluginCliContext): PluginCliResult | Promise;\n}\ninterface PluginCli {\n /**\n * Register this plugin's `bb` subcommand. One registration per factory\n * execution; a repeated call is rejected. Core bb commands always win\n * name collisions; reserved names are rejected at registration.\n */\n register(registration: PluginCliRegistration): void;\n}\n/** Per-turn context handed to bb.agents context providers (design §4.4). */\n/** MCP-style content parts a native tool may return (design §4.4). */\ntype PluginAgentToolContentPart = {\n type: \"text\";\n text: string;\n} | {\n type: \"image\";\n data: string;\n mimeType: string;\n};\ntype PluginAgentToolResult = string | {\n content: PluginAgentToolContentPart[];\n isError?: boolean;\n};\n/** Per-call context handed to a native tool's execute (design §4.4). */\ninterface PluginAgentToolContext {\n threadId: string;\n projectId: string;\n /** The tool-call request's abort signal (aborts if the daemon round-trip\n * is torn down mid-call). */\n signal: AbortSignal;\n}\ninterface PluginAgentToolRegistrationBase {\n /** Tool name shown to the model: [a-zA-Z0-9_-]+, unique across plugins,\n * and not a built-in dynamic tool (see RESERVED_AGENT_TOOL_NAMES in the\n * server). */\n name: string;\n description: string;\n /**\n * Optional usage snippet appended to the thread instructions whenever\n * this tool is in the session's tool set (mirrors the built-in\n * update_environment_directory guidance). Limited to 4096 characters.\n */\n instructions?: string;\n}\n/** Stable, plain-data context resolved by the server for one agent session. */\ninterface PluginAgentConfigurationContext {\n thread: {\n id: string;\n title: string | null;\n parentThreadId: string | null;\n sourceThreadId: string | null;\n };\n project: {\n id: string;\n kind: \"standard\" | \"personal\";\n name: string;\n gitRemoteUrl: string | null;\n };\n environment: {\n id: string;\n name: string | null;\n path: string | null;\n workspaceProvisionType: \"unmanaged\" | \"managed-worktree\" | \"personal\";\n branchName: string | null;\n };\n host: {\n id: string;\n name: string;\n };\n provider: {\n id: string;\n model: string;\n };\n sideChat: boolean;\n origin: {\n kind: \"fork\" | \"side-chat\" | null;\n pluginId: string | null;\n };\n}\n/** Object form of a {@link PluginAgentConfiguration} tools entry: selects a\n * registered tool and overrides the parameter schema advertised to the\n * provider for this resolution only. */\ninterface PluginAgentToolSelection {\n /** Name of a tool registered by this plugin via `registerTool`. */\n name: string;\n /** JSON-schema object (root `type: \"object\"`, JSON-serializable, at most\n * 128 KiB serialized) sent to the provider in place of the registered\n * parameter schema. Execution-side validation still runs the registered\n * parameters, so the override must only narrow what the registered schema\n * already accepts. */\n parameters: Record;\n}\n/** Per-resolution selection returned by {@link PluginAgents.configure}. */\ninterface PluginAgentConfiguration {\n /** Tool names registered by this plugin, or {@link PluginAgentToolSelection}\n * entries to also override a tool's advertised parameter schema for this\n * resolution. Duplicate or unknown names, or an invalid override, reject\n * this plugin's complete selection for the resolution. */\n tools: Array;\n /** Skill frontmatter names from this plugin's manifest skill roots.\n * Duplicate or unknown names reject this plugin's complete selection. */\n skills: string[];\n /** Optional dynamic instructions. Output is truncated to 4096 characters. */\n instructions?: string;\n}\ninterface PluginAgents {\n /**\n * Select this plugin's statically registered tools and manifest skills for\n * each thread/session resolution, with optional dynamic instructions. The\n * callback is synchronous and runs at `thread.start` / `turn.submit`; it\n * never rebuilds registrations. Exactly one callback may be registered per\n * factory execution. A throw, malformed result, duplicate id, unknown id,\n * or more than 256 tool/skill ids fails closed for this plugin only.\n *\n * Tools take effect when the provider session is next started or resumed;\n * an already-running session is not hot-mutated. Instructions are resolved\n * for the next turn. Skill changes follow BB's environment runtime policy:\n * a busy runtime keeps its current catalog until a safe relaunch. Side-chat\n * threads receive `sideChat: true`, and their returned tool, skill, and\n * dynamic-instruction selections apply at the same boundaries. Independent\n * side-chat safety policy (such as permission escalation) is unchanged.\n */\n configure(provider: (context: PluginAgentConfigurationContext) => PluginAgentConfiguration): void;\n /**\n * Register a native dynamic tool (design §4.4). `parameters` is either a\n * zod schema (validated per call; execute receives the parsed value) or a\n * plain JSON-schema object (no validation; execute receives the raw\n * arguments as `unknown`). Tool-set changes apply on the NEXT session\n * start — a tool registered mid-session is not hot-added to running\n * provider sessions. A second registration of the same name within this\n * plugin is rejected; a name already registered by another plugin is\n * rejected and surfaced as this plugin's status detail.\n */\n registerTool(tool: PluginAgentToolRegistrationBase & {\n parameters: Schema;\n execute(params: z.output, ctx: PluginAgentToolContext): PluginAgentToolResult | Promise;\n }): void;\n registerTool(tool: PluginAgentToolRegistrationBase & {\n /** Raw JSON-schema escape hatch; params arrive unvalidated. */\n parameters: Record;\n execute(params: unknown, ctx: PluginAgentToolContext): PluginAgentToolResult | Promise;\n }): void;\n /**\n * Contribute a dynamic section appended to thread instructions. The\n * provider runs when a thread's runtime command config is resolved\n * (thread.start / turn.submit); return null to contribute nothing for\n * that resolution. Must be synchronous and fast — it sits on the\n * thread-start path. Output longer than 4096 characters is truncated; a\n * throwing provider is logged against the plugin and contributes nothing.\n * A repeated registration within one factory execution is rejected.\n * This legacy contribution is not applied to side-chat threads; use\n * configure() when sideChat-aware dynamic instructions are required.\n */\n contributeInstructions(provider: (ctx: {\n threadId: string;\n projectId: string;\n }) => string | null): void;\n}\ninterface PluginThreadActionContext {\n threadId: string;\n projectId: string;\n}\ninterface PluginThreadActionToast {\n kind: \"success\" | \"error\" | \"info\";\n message: string;\n}\ntype PluginThreadActionResult = void | {\n toast?: PluginThreadActionToast;\n};\ninterface PluginThreadActionRegistration {\n /** Unique within this plugin: [a-zA-Z0-9_-]+ (becomes a URL segment). */\n id: string;\n /** Button label rendered in the thread header. */\n title: string;\n /** Optional icon name; the host falls back to a generic icon. */\n icon?: string;\n /** Optional confirmation prompt the host shows before running. */\n confirm?: string;\n /**\n * Runs server-side when the user clicks the action. The host shows a\n * pending state while in flight, the returned toast on completion, and an\n * automatic error toast when this throws.\n */\n run(ctx: PluginThreadActionContext): PluginThreadActionResult | Promise;\n}\ntype PluginMentionTrigger = \"@\" | \"#\" | \"$\" | \"!\" | \"~\";\n/** Search context handed to a mention provider (design §4.9). `projectId`/\n * `threadId` are null when the composer has not committed one yet. */\ninterface PluginMentionSearchContext {\n trigger: PluginMentionTrigger;\n query: string;\n projectId: string | null;\n threadId: string | null;\n}\n/** One row a mention provider returns from `search`. `id` is the provider's\n * own item id — the host namespaces it before it reaches the wire. */\ninterface PluginMentionItem {\n id: string;\n title: string;\n subtitle?: string;\n icon?: string;\n}\ninterface PluginMentionProviderRegistration {\n /** Unique within this plugin: [a-zA-Z0-9_-]+ (no \":\" — the host composes\n * wire item ids as \":\"). */\n id: string;\n /** Section label shown above this provider's rows in the mention menu. */\n label: string;\n /**\n * Composer trigger characters this provider should answer. Omit to use the\n * default `@` mention trigger. Valid triggers are `@`, `#`, `$`, `!`, and `~`.\n */\n triggers?: readonly PluginMentionTrigger[];\n /**\n * Runs server-side as the user types after one of this provider's triggers\n * in the composer. Each call is time-boxed (2s) and failure-isolated: a slow\n * or throwing provider contributes an empty list — it can never break the\n * mention menu.\n */\n search(ctx: PluginMentionSearchContext): PluginMentionItem[] | Promise;\n /**\n * Resolves one picked item into agent context, called once per unique\n * item at message send time. The returned `context` is attached to the\n * message as an agent-visible (user-hidden) prompt input. Throwing blocks\n * the send with a visible error.\n */\n resolve(itemId: string): {\n context: string;\n } | Promise<{\n context: string;\n }>;\n}\ninterface PluginUi {\n /** Block until the app submits or cancels a plugin-owned composer form. */\n requestInput(request: PluginInteractionRequest, options?: {\n signal?: AbortSignal;\n }): Promise;\n /**\n * Register a thread action rendered in the shipped app's thread header\n * (design §4.9). Multiple actions per plugin; ids must be unique within\n * the plugin. Invoked via POST /plugins/:id/actions/:actionId.\n */\n registerThreadAction(action: PluginThreadActionRegistration): void;\n /**\n * Register a mention provider for the shipped app's composer (design §4.9).\n * Providers default to the `@` trigger and may opt into `#`, `$`, `!`, or\n * `~` with `triggers`. Items group under `label` in the mention menu; a\n * picked item becomes a `{ kind: \"plugin\" }` mention resource whose context\n * is resolved once at send time. Multiple providers per plugin; ids must be\n * unique within the plugin.\n */\n registerMentionProvider(provider: PluginMentionProviderRegistration): void;\n}\ninterface PluginEvents {\n /**\n * Add a thread lifecycle listener. Multiple listeners for the same event are\n * additive and run independently in registration order.\n */\n on(event: E, handler: PluginThreadEventHandler): void;\n}\ninterface PluginServerApi {\n /**\n * This BB server's own loopback base URL (e.g. \"http://127.0.0.1:38886\"),\n * which serves the SPA + /api + /ws. For plugins that proxy or relay\n * traffic back to the server itself (e.g. a tunnel). Bind-gated like\n * `bb.sdk`: reading it before the server is listening throws, so prefer\n * reading it from handlers, services, and timers.\n */\n readonly loopbackBaseUrl: string;\n}\ninterface PluginSharedPortTunnelIdentity {\n /** Gate routing label assigned to this machine. */\n label: string;\n /** Gate apex without a scheme, e.g. \"getbb.app\". */\n baseDomain: string;\n}\ninterface PluginHosts {\n /**\n * Ensure this enrolled host has a gate label and return its read-only public\n * identity. The daemon chooses the trusted gate and desired label; plugins\n * cannot influence either credential-bearing destination.\n */\n ensureSharedPortTunnel(hostId: string): Promise;\n /**\n * Replace this plugin's desired shared-loopback ports for one host. The\n * server aggregates declarations, owns generations, and delivers the\n * resulting set to that host's daemon. Tunnel identity is deliberately not\n * accepted here: it is owned by the daemon's trusted enrollment.\n */\n declareSharedPorts(hostId: string, ports: readonly number[]): void;\n}\ninterface PluginStatusApi {\n /**\n * Mark this plugin `needs-configuration` (with a message shown in\n * `bb plugin list` and the UI) instead of failing — e.g. a factory or\n * service that finds no API key configured. Cleared on the next load;\n * saving settings does not auto-reload in V1, so ask the user to\n * `bb plugin reload ` after configuring.\n */\n needsConfiguration(message: string): void;\n}\n/**\n * The API object handed to a plugin's factory (design §4). Implemented by\n * the BB server; this contract is what plugin `server.ts` files compile\n * against.\n */\ninterface BbPluginApi {\n /** The plugin's own id (namespaces storage, routes, commands). */\n readonly pluginId: string;\n /** Leveled, plugin-scoped logger. */\n readonly log: PluginLogger;\n /** Declarative settings (design §4.2). */\n readonly settings: PluginSettings;\n /** Namespaced KV + per-plugin database (design §4.3). */\n readonly storage: PluginStorage;\n /** HTTP routes under /api/v1/plugins//http/* (design §4.6). */\n readonly http: PluginHttp;\n /** RPC methods under /api/v1/plugins//rpc/ (design §4.6). */\n readonly rpc: PluginRpc;\n /** Ephemeral push to connected frontends (design §4.7). */\n readonly realtime: PluginRealtime;\n /** Long-lived services + cron schedules (design §4.8). */\n readonly background: PluginBackground;\n /** Agent-facing `bb` CLI subcommand (design §4.4). */\n readonly cli: PluginCli;\n /** Per-turn agent context contributions (design §4.4). */\n readonly agents: PluginAgents;\n /** Host-rendered UI contributions (design §4.9). */\n readonly ui: PluginUi;\n /** Additive plugin lifecycle listeners (design §4.5). */\n readonly events: PluginEvents;\n /** Plugin-reported status (needs-configuration). */\n readonly status: PluginStatusApi;\n /** Read-only facts about the running server (loopback base URL). */\n readonly server: PluginServerApi;\n /** Server-to-daemon host control-plane declarations. */\n readonly hosts: PluginHosts;\n /**\n * The full BB SDK, bound to this server over loopback (design §4.1).\n * Bind-gated: reading this before the host binds the SDK throws. The real\n * server binds it before loading plugins, so it is available from the\n * moment factories run there — but isolated harnesses may not, so prefer\n * using it from handlers, services, and timers for portability.\n * `threads.spawn` defaults `origin` to \"plugin\" and `originPluginId` to\n * this plugin's id so spawned threads are attributed automatically.\n */\n readonly sdk: BbSdk;\n /**\n * Register cleanup to run on reload/disable/shutdown. Hooks run LIFO.\n * The sanctioned place to clear timers and close connections.\n */\n onDispose(hook: () => void | Promise): void;\n}\n\nexport { PLUGIN_CLI_OUTPUT_MAX_BYTES, defineRpcContract };\nexport type { BbContext, BbNavigate, BbPluginApi, JsonValue$1 as JsonValue, PluginAgentConfiguration, PluginAgentConfigurationContext, PluginAgentToolContentPart, PluginAgentToolContext, PluginAgentToolRegistrationBase, PluginAgentToolResult, PluginAgentToolSelection, PluginAgents, PluginAppBuilder, PluginAppDefinition, PluginAppSetup, PluginAppSlots, PluginBackground, PluginCli, PluginCliCommandInfo, PluginCliContext, PluginCliExecutionResult, PluginCliOutputLimitError, PluginCliRegistration, PluginCliResult, PluginComposerAccessoryProps, PluginComposerAccessoryRegistration, PluginComposerApi, PluginComposerMention, PluginComposerScope, PluginEvents, PluginFileOpenerProps, PluginFileOpenerRegistration, PluginFileOpenerSource, PluginHomepageSectionProps, PluginHomepageSectionRegistration, PluginHosts, PluginHttp, PluginHttpAuthMode, PluginHttpHandler, PluginInteractionCancelReason, PluginInteractionRequest, PluginInteractionResult, PluginKvStorage, PluginLogger, PluginMentionItem, PluginMentionProviderRegistration, PluginMentionSearchContext, PluginMentionTrigger, PluginMessageDirectiveMessage, PluginMessageDirectiveOpenThreadPanel, PluginMessageDirectiveOpenWorkspaceFile, PluginMessageDirectiveProps, PluginMessageDirectiveRegistration, PluginMessageDirectiveThreadPanelOptions, 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 };\n"; export const PLUGIN_SDK_APP_DTS = "// Portable type declarations for `@bb/plugin-sdk`. Unpublished BB\n// workspace contracts are flattened; public subpaths may reuse the\n// package root without requiring any other @bb/* package.\n//\n// Confused by the API, or need a symbol that isn't here? Clone the BB repo\n// and read the real source: https://github.com/ymichael/bb\n\nimport { ComponentType } from 'react';\n\n/** A JSON-safe path segment reported by a Standard Schema validation issue. */\ntype PluginRpcIssuePathSegment = string | number;\n/** Validator-neutral validation detail carried by an RPC error envelope. */\ninterface PluginRpcValidationIssue {\n message: string;\n path?: PluginRpcIssuePathSegment[];\n}\n/** Stable wire error categories for plugin RPC. */\ntype PluginRpcErrorCode = \"invalid_json\" | \"invalid_input\" | \"handler_error\" | \"invalid_output\" | \"non_json_result\" | \"unknown_method\";\n/** Structured RPC failure returned as `{ ok: false, error }`. */\ninterface PluginRpcError {\n code: PluginRpcErrorCode;\n message: string;\n issues?: PluginRpcValidationIssue[];\n}\n/**\n * The validator-neutral subset of Standard Schema v1 used by plugin RPC.\n * Zod 4 schemas implement this interface directly; other validators can do\n * the same without becoming part of BB's public protocol.\n */\ninterface StandardSchemaV1 {\n readonly \"~standard\": {\n readonly version: 1;\n readonly vendor: string;\n readonly validate: (value: unknown) => StandardSchemaV1Result | Promise>;\n readonly types?: {\n readonly input: Input;\n readonly output: Output;\n };\n };\n}\ntype StandardSchemaV1Result = {\n readonly value: Output;\n readonly issues?: undefined;\n} | {\n readonly issues: readonly StandardSchemaV1Issue[];\n};\ninterface StandardSchemaV1Issue {\n readonly message: string;\n readonly path?: PropertyKey | readonly (PropertyKey | {\n readonly key: PropertyKey;\n })[];\n}\ntype StandardSchemaV1InferInput = NonNullable[\"input\"];\ntype StandardSchemaV1InferOutput = NonNullable[\"output\"];\ninterface PluginRpcMethodContract {\n readonly input: InputSchema;\n readonly output: OutputSchema;\n}\ntype PluginRpcContract = Readonly>;\ntype PluginRpcHandlers = {\n [Method in keyof Contract]: (input: StandardSchemaV1InferOutput) => StandardSchemaV1InferInput | Promise>;\n};\ntype PluginRpcCallInput = StandardSchemaV1InferInput;\ntype PluginRpcCallArgs = null extends PluginRpcCallInput ? [input?: PluginRpcCallInput] : [input: PluginRpcCallInput];\ntype PluginRpcResult = StandardSchemaV1InferOutput;\n\n/**\n * A value that survives a JSON round trip without coercion or data loss.\n *\n * Host boundaries still validate values at runtime because TypeScript cannot\n * exclude non-finite numbers and plugin bundles can bypass static types.\n */\ntype JsonValue = string | number | boolean | null | JsonValue[] | {\n [key: string]: JsonValue;\n};\n\n/**\n * The `@bb/plugin-sdk/app` contract (plugin design §5.2) — pure types with no\n * side effects. The BB app imports these to keep its real implementation in\n * sync (`satisfies PluginSdkApp`). Plugin authors import the same shapes through\n * `@bb/plugin-sdk/app`.\n *\n * Per-slot props are versioned contracts: additive-only within an SDK major.\n */\n/** Props passed to a `homepageSection` component. */\ninterface PluginHomepageSectionProps {\n /** Project in view on the compose surface; null when none is selected. */\n projectId: string | null;\n}\n/**\n * Props passed to a `settingsSection` component.\n *\n * Deliberately empty in V1; versioned additive like the other slot props.\n */\ninterface PluginSettingsSectionProps {\n}\n/** Props passed to a `navPanel` component (it owns its whole route). */\ninterface PluginNavPanelProps {\n /**\n * The route remainder after the panel root, \"\" at the root. The panel's\n * route is `/plugins///*`, so a deep link like\n * `/plugins/notes/notes/work/ideas.md` renders the panel with\n * `subPath: \"work/ideas.md\"`. Navigate within the panel via\n * `useBbNavigate().toPluginPanel(path, { subPath })` — browser\n * back/forward then walks panel-internal history.\n */\n subPath: string;\n}\n/** Props passed to a panel tab opened by a `threadPanelAction`. */\ninterface PluginThreadPanelProps {\n threadId: string;\n /**\n * The JSON value the action's `openPanel` call passed (round-tripped\n * through persistence, so the tab restores across reloads); null when the\n * action opened the panel without params.\n */\n params: JsonValue | null;\n}\n/** Props passed to a `composerAccessory` component. */\ninterface PluginComposerAccessoryProps {\n projectId: string | null;\n threadId: string | null;\n}\ninterface PluginPendingInteractionView {\n id: string;\n threadId: string;\n title: string;\n payload: JsonValue;\n createdAt: number;\n expiresAt: number | null;\n}\ninterface PluginPendingInteractionProps {\n interaction: PluginPendingInteractionView;\n submit(value: JsonValue): Promise;\n cancel(): Promise;\n}\n/**\n * Props for a `sidebarFooterAction` — host-rendered (no plugin component).\n * Deliberately empty; the registration's `run` carries the behavior.\n */\ninterface PluginSidebarFooterActionProps {\n}\n/**\n * Where a file being opened by a `fileOpener` lives. `path` semantics follow\n * the source: workspace paths are relative to the environment's worktree,\n * thread-storage paths are relative to the thread's storage root, host paths\n * are absolute on the thread's host.\n */\ninterface PluginFileOpenerSource {\n kind: \"workspace\" | \"host\" | \"thread-storage\";\n threadId: string | null;\n environmentId: string | null;\n projectId: string | null;\n}\n/** Props passed to a `fileOpener` component (rendered as a panel file tab). */\ninterface PluginFileOpenerProps {\n path: string;\n source: PluginFileOpenerSource;\n}\n/**\n * Message context passed to a `messageDirective` component — the assistant\n * (or nested agent) message that contained the directive.\n */\ninterface PluginMessageDirectiveMessage {\n id: string;\n threadId: string;\n turnId: string | null;\n projectId: string | null;\n}\n/**\n * Open a worktree-relative file in the host's workspace file viewer. Returns\n * true when the host accepted the path; false when the path is invalid or the\n * viewer declined it.\n */\ntype PluginMessageDirectiveOpenWorkspaceFile = (path: string) => boolean;\ninterface PluginMessageDirectiveThreadPanelOptions {\n /** A `threadPanelAction` id registered by this same plugin. */\n actionId: string;\n title?: string;\n params?: JsonValue;\n}\n/** Open this plugin's registered action in the current thread side panel. */\ntype PluginMessageDirectiveOpenThreadPanel = (options: PluginMessageDirectiveThreadPanelOptions) => boolean;\n/**\n * Props passed to a `messageDirective` component. Attributes are untrusted\n * strings parsed from the directive; the plugin validates its own fields.\n */\ninterface PluginMessageDirectiveProps {\n /** Parsed, untrusted directive attributes (e.g. `{ file: \"demo.html\" }`). */\n attributes: Readonly>;\n /** Original directive source text (useful for diagnostics / crash fallback). */\n source: string;\n message: PluginMessageDirectiveMessage;\n /**\n * Opens a worktree-relative file in the host's workspace file viewer. Null\n * when the message surface has no workspace viewer available.\n */\n openWorkspaceFile: PluginMessageDirectiveOpenWorkspaceFile | null;\n /**\n * Opens one of this plugin's own `threadPanelAction` components in the\n * current thread side panel. Omitted by older hosts; null on message\n * surfaces without a thread panel.\n */\n openThreadPanel?: PluginMessageDirectiveOpenThreadPanel | null;\n}\ninterface PluginHomepageSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n component: ComponentType;\n}\ninterface PluginSettingsSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Optional host-rendered section heading. */\n title?: string;\n /**\n * Optional one-line host-rendered subheading under `title`, in the built-in\n * SettingsSection idiom (ignored when `title` is absent).\n */\n description?: string;\n component: ComponentType;\n}\ninterface PluginNavPanelRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /** URL segment under `/plugins//`; letters, digits, `-`, `_`. */\n path: string;\n component: ComponentType;\n /**\n * Optional component rendered on the right side of the shared title bar\n * (e.g. a sync button or a count). Contained separately from the body: a\n * throwing headerContent is hidden without breaking the title bar.\n */\n headerContent?: ComponentType;\n}\n/** Context handed to a `threadPanelAction`'s `run`. */\ninterface PluginThreadPanelActionContext {\n /** The thread whose panel launcher invoked the action. */\n threadId: string;\n /**\n * Open a tab in the thread's side panel rendering this action's\n * `component`. `title` labels the tab (default: the action's `title`);\n * `params` must be JSON-serializable — it is persisted with the tab and\n * reaches the component as its `params` prop. Opening with params\n * identical to an already-open tab of this action focuses that tab\n * (updating its title) instead of duplicating it. May be called more than\n * once (different params ⇒ multiple tabs) or not at all.\n */\n openPanel(options?: {\n title?: string;\n params?: JsonValue;\n }): void;\n}\ninterface PluginThreadPanelActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label of the action row in the panel's new-tab launcher. */\n title: string;\n /**\n * Icon hint (BB icon name) used when the plugin ships no logo; the\n * launcher row and opened tabs prefer the plugin's logo.\n */\n icon?: string;\n /** Rendered inside every panel tab this action opens. */\n component: ComponentType;\n /**\n * Runs when the user activates the action: call your RPC methods, show a\n * toast, and/or open panel tabs via `context.openPanel`. Omitted =\n * immediately open a panel tab with defaults. Errors (sync or async) are\n * contained and logged; they never break the launcher.\n */\n run?(context: PluginThreadPanelActionContext): void | Promise;\n}\ninterface PluginComposerAccessoryRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n component: ComponentType;\n}\ninterface PluginPendingInteractionRegistration {\n /** Matches `rendererId` passed to `bb.ui.requestInput`. */\n id: string;\n component: ComponentType;\n}\n/** Context handed to a `sidebarFooterAction`'s `run`. */\ninterface PluginSidebarFooterActionContext {\n /**\n * Navigate to this plugin's Settings detail page\n * (`/settings/plugins/`), where declarative settings and\n * `settingsSection` slots render.\n */\n openSettings(): void;\n}\n/**\n * An icon button in the app sidebar footer (next to Settings / bug report).\n * Host-rendered for consistent chrome — plugins supply icon, label, and\n * `run` behavior only.\n */\ninterface PluginSidebarFooterActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Tooltip and accessible label for the icon button. */\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /**\n * Runs when the user activates the action (e.g. call `openSettings()`,\n * open a panel via other surfaces, toast). Errors (sync or async) are\n * contained and logged; they never break the sidebar.\n */\n run(context: PluginSidebarFooterActionContext): void | Promise;\n}\n/**\n * Register this plugin as a viewer/editor for file extensions. The user\n * picks (and can set as default) an opener per extension via the file tab's\n * \"Open with\" menu; matching files opened in the panel then render\n * `component` in a plugin tab instead of the built-in preview. Applies to\n * working-tree, host, and thread-storage files — never to git-ref snapshots\n * (diff views always use the built-in preview). The built-in preview stays\n * one menu click away, and a missing/disabled opener falls back to it.\n */\ninterface PluginFileOpenerRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label in the \"Open with\" menu (e.g. \"Notes editor\"). */\n title: string;\n /** Lowercase extensions without the dot (e.g. [\"md\", \"mdx\"]). */\n extensions: readonly string[];\n component: ComponentType;\n}\n/**\n * Register a leaf message directive rendered inside assistant (and nested\n * agent) message Markdown. `id` is the directive name: `inline-vis` matches\n * `::inline-vis{file=\"demo.html\"}`.\n */\ninterface PluginMessageDirectiveRegistration {\n /**\n * The directive name. Lowercase kebab-case beginning with a letter.\n */\n id: string;\n component: ComponentType;\n}\ninterface PluginAppSlots {\n homepageSection(registration: PluginHomepageSectionRegistration): void;\n settingsSection(registration: PluginSettingsSectionRegistration): void;\n navPanel(registration: PluginNavPanelRegistration): void;\n threadPanelAction(registration: PluginThreadPanelActionRegistration): void;\n composerAccessory(registration: PluginComposerAccessoryRegistration): void;\n pendingInteraction(registration: PluginPendingInteractionRegistration): void;\n sidebarFooterAction(registration: PluginSidebarFooterActionRegistration): void;\n fileOpener(registration: PluginFileOpenerRegistration): void;\n messageDirective(registration: PluginMessageDirectiveRegistration): void;\n}\ninterface PluginAppBuilder {\n slots: PluginAppSlots;\n}\ntype PluginAppSetup = (app: PluginAppBuilder) => void;\n/**\n * The opaque product of `definePluginApp` — a plugin's `app.tsx` default\n * export. The host re-runs `setup` against a fresh collector on every\n * (re)interpretation, replacing that plugin's registrations wholesale.\n */\ninterface PluginAppDefinition {\n /** Brand the host checks before interpreting a bundle's default export. */\n readonly __bbPluginApp: true;\n readonly setup: PluginAppSetup;\n}\ninterface PluginRpcClient {\n /**\n * Invoke one of the plugin's `bb.rpc` methods (POST\n * /api/v1/plugins/<id>/rpc/<method>). Resolves with the method's\n * inferred output; rejects with an `Error` carrying the server's message,\n * stable `code`, and validation `issues` when present.\n */\n call>(method: Method, ...args: PluginRpcCallArgs): Promise>;\n}\ninterface PluginSettingsState {\n /**\n * Effective non-secret setting values (secret settings are excluded —\n * read them server-side). Undefined while loading or unavailable.\n */\n values: Record | undefined;\n isLoading: boolean;\n}\n/** State of the app's shared realtime connection to the bb server. */\ntype PluginRealtimeConnectionState = \"connecting\" | \"connected\" | \"reconnecting\";\n/** Where `useComposer()` writes: the active thread's draft or the new-thread draft. */\ntype PluginComposerScope = {\n kind: \"thread\";\n threadId: string;\n} | {\n kind: \"new-thread\";\n projectId: string | null;\n};\n/** An @-mention pill bound to one of the calling plugin's mention providers. */\ninterface PluginComposerMention {\n /** Mention provider id registered by THIS plugin via `bb.ui.registerMentionProvider`. */\n provider: string;\n /** Item id your provider's `resolve` will receive at send time. */\n id: string;\n /** Pill text shown in the composer. */\n label: string;\n}\n/**\n * Programmatic access to the chat composer draft — the same shared draft the\n * built-in \"Add to chat\" affordances (file preview, diff, terminal selections)\n * write to. Inside a thread context writes land in that thread's draft;\n * anywhere else (nav panel, homepage section) they seed the new-thread\n * composer draft, which persists until the user sends or clears it.\n */\ninterface PluginComposerApi {\n scope: PluginComposerScope;\n /** Current plain text for this composer scope. */\n readonly text: string;\n /**\n * Replace the draft's plain text. Attachments are preserved. Inline mentions\n * outside the changed range are preserved and rebased; mentions overlapped\n * by the replacement are removed because their text representation changed.\n */\n setText(next: string): void;\n /**\n * Replace the draft's plain text from the latest committed value. Uses the\n * same structured-state reconciliation as `setText`.\n */\n updateText(updater: (current: string) => string): void;\n /** Clear plain text without clearing independently attached files. */\n clear(): void;\n /**\n * Append text to the draft as a `> ` blockquote block and focus the\n * composer. Blank text is a no-op. This is the \"reference this selection\n * in chat\" primitive.\n */\n addQuote(text: string): void;\n /**\n * Insert an @-mention pill that resolves through this plugin's mention\n * provider at send time — the durable way to reference an entity whose\n * content should be fetched fresh when the message is sent.\n */\n insertMention(mention: PluginComposerMention): void;\n /** Focus the composer caret at the end of the draft. */\n focus(): void;\n}\n/** Current app selection, derived from the route. */\ninterface BbContext {\n projectId: string | null;\n threadId: string | null;\n}\ninterface BbNavigate {\n toThread(threadId: string): void;\n toProject(projectId: string): void;\n /**\n * Navigate to one of this plugin's own nav panels by its `path`.\n * `subPath` targets a location inside the panel (the component's\n * `subPath` prop); `replace` swaps the current history entry instead of\n * pushing — use it for redirects so back does not bounce.\n */\n toPluginPanel(path: string, options?: {\n subPath?: string;\n replace?: boolean;\n }): void;\n /**\n * Navigate to the root compose surface (the new-thread screen). Pass\n * `initialPrompt` to seed the composer draft and `focusPrompt` to focus the\n * composer on arrival — the pairing behind \"Create via chat\" style entry\n * points that drop the user into chat with a prefilled prompt.\n */\n toCompose(options?: {\n initialPrompt?: string;\n focusPrompt?: boolean;\n }): void;\n}\n/**\n * Everything `@bb/plugin-sdk/app` resolves to at runtime. The BB app builds\n * the real implementation and `satisfies` this interface; `bb plugin build`\n * shims the specifier to that object on `globalThis.__bbPluginRuntime`.\n */\ninterface PluginSdkApp {\n definePluginApp(setup: PluginAppSetup): PluginAppDefinition;\n useRpc(): PluginRpcClient;\n useRealtime(channel: string, handler: (payload: unknown) => void): void;\n /**\n * Observe the same shared connection that delivers `useRealtime` signals.\n * Use a subsequent transition to `connected` to reconcile server state that\n * may have changed while ephemeral signals could not be delivered. The first\n * connection can transition from `connecting` and is not a reconnection.\n */\n useRealtimeConnectionState(): PluginRealtimeConnectionState;\n useSettings(): PluginSettingsState;\n useBbContext(): BbContext;\n useBbNavigate(): BbNavigate;\n useComposer(): PluginComposerApi;\n}\n\ndeclare const definePluginApp: (setup: PluginAppSetup) => PluginAppDefinition;\ndeclare const useRpc: , StandardSchemaV1>>>>() => PluginRpcClient;\ndeclare const useRealtime: (channel: string, handler: (payload: unknown) => void) => void;\ndeclare const useRealtimeConnectionState: () => PluginRealtimeConnectionState;\ndeclare const useSettings: () => PluginSettingsState;\ndeclare const useBbContext: () => BbContext;\ndeclare const useBbNavigate: () => BbNavigate;\ndeclare const useComposer: () => PluginComposerApi;\n\nexport { definePluginApp, useBbContext, useBbNavigate, useComposer, useRealtime, useRealtimeConnectionState, useRpc, useSettings };\nexport type { BbContext, BbNavigate, JsonValue, PluginAppBuilder, PluginAppDefinition, PluginAppSetup, PluginAppSlots, PluginComposerAccessoryProps, PluginComposerAccessoryRegistration, PluginComposerApi, PluginComposerMention, PluginComposerScope, PluginFileOpenerProps, PluginFileOpenerRegistration, PluginFileOpenerSource, PluginHomepageSectionProps, PluginHomepageSectionRegistration, PluginMessageDirectiveMessage, PluginMessageDirectiveOpenThreadPanel, PluginMessageDirectiveOpenWorkspaceFile, PluginMessageDirectiveProps, PluginMessageDirectiveRegistration, PluginMessageDirectiveThreadPanelOptions, 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 };\n"; diff --git a/packages/thread-view/src/build-thread-timeline.ts b/packages/thread-view/src/build-thread-timeline.ts index 73ae0dbf0b..5f2bc81a3f 100644 --- a/packages/thread-view/src/build-thread-timeline.ts +++ b/packages/thread-view/src/build-thread-timeline.ts @@ -553,6 +553,7 @@ function convertMessage( attachments: toConversationAttachments(message.attachments), initiator: message.initiator, senderThreadId: message.senderThreadId, + actorHandle: message.actorHandle, systemMessageKind: message.systemMessageKind, systemMessageSubject: message.systemMessageSubject, turnRequest: message.turnRequest, @@ -811,6 +812,7 @@ function convertPendingSteerMessage( attachments: toConversationAttachments(message.attachments), initiator: message.initiator, senderThreadId: message.senderThreadId, + actorHandle: message.actorHandle, systemMessageKind: message.systemMessageKind, systemMessageSubject: message.systemMessageSubject, turnRequest: message.turnRequest, diff --git a/packages/thread-view/src/event-decode.ts b/packages/thread-view/src/event-decode.ts index fc4f7044f4..d227d2a1a8 100644 --- a/packages/thread-view/src/event-decode.ts +++ b/packages/thread-view/src/event-decode.ts @@ -116,6 +116,9 @@ export interface EventMeta { id: string; seq: number; createdAt: number; + // Claimed handle of the human who initiated the event; null = not + // human-initiated or pre-multiplayer history. + actorHandle: string | null; } function buildEventMeta(row: ThreadEventRow): EventMeta { @@ -123,6 +126,7 @@ function buildEventMeta(row: ThreadEventRow): EventMeta { id: row.id, seq: row.seq, createdAt: row.createdAt, + actorHandle: row.actorHandle, }; } diff --git a/packages/thread-view/src/event-projection-message.ts b/packages/thread-view/src/event-projection-message.ts index d1dac7c244..574b283318 100644 --- a/packages/thread-view/src/event-projection-message.ts +++ b/packages/thread-view/src/event-projection-message.ts @@ -86,6 +86,9 @@ export interface EventProjectionUserMessage extends EventProjectionMessageBase { kind: "user"; initiator: ThreadTurnInitiator; senderThreadId: string | null; + // Claimed handle of the human author; null = not human-initiated or + // pre-multiplayer history. + actorHandle: string | null; // Family-B taxonomy fields carried from the decoded `client/turn/requested` // event. Legacy events lacking them project as `unlabeled` / `null`. systemMessageKind: SystemMessageKind; diff --git a/packages/thread-view/src/parse-error-message.ts b/packages/thread-view/src/parse-error-message.ts index ecee678590..fbd9ce9f35 100644 --- a/packages/thread-view/src/parse-error-message.ts +++ b/packages/thread-view/src/parse-error-message.ts @@ -146,6 +146,7 @@ export function appendDebugEvent( threadId: decoded.threadId, seq: meta.seq, createdAt: meta.createdAt, + actorHandle: meta.actorHandle, event: decoded, }), reason, diff --git a/packages/thread-view/src/user-message-parsing.ts b/packages/thread-view/src/user-message-parsing.ts index 69c3e8cc50..5802d8d3ad 100644 --- a/packages/thread-view/src/user-message-parsing.ts +++ b/packages/thread-view/src/user-message-parsing.ts @@ -307,6 +307,7 @@ function buildClientUserMessage({ : { scope: decoded.scope }), initiator, senderThreadId, + actorHandle: rowMeta.actorHandle, // Legacy defaulting lives in `storedTurnRequestEventDataSchema`, so decoded // rows always carry concrete values at runtime. These `??` fallbacks only // satisfy the base in-flight schema's `.optional()` static type; they never diff --git a/packages/thread-view/test/accepted-client-request-context.test.ts b/packages/thread-view/test/accepted-client-request-context.test.ts index ec8c2a1603..fcd8f06d1c 100644 --- a/packages/thread-view/test/accepted-client-request-context.test.ts +++ b/packages/thread-view/test/accepted-client-request-context.test.ts @@ -30,6 +30,7 @@ function inputAcceptedEvent({ clientRequestId, }, meta: { + actorHandle: null, createdAt, id: eventId, seq: sequence, diff --git a/packages/thread-view/test/background-task-timeline.test.ts b/packages/thread-view/test/background-task-timeline.test.ts index a7f90ed794..098152b4b6 100644 --- a/packages/thread-view/test/background-task-timeline.test.ts +++ b/packages/thread-view/test/background-task-timeline.test.ts @@ -17,6 +17,7 @@ function withMeta(event: ThreadEvent, seq: number): ThreadEventWithMeta { return { event, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq * 1_000, diff --git a/packages/thread-view/test/build-thread-timeline.test.ts b/packages/thread-view/test/build-thread-timeline.test.ts index c6f7f81e5e..43503d2758 100644 --- a/packages/thread-view/test/build-thread-timeline.test.ts +++ b/packages/thread-view/test/build-thread-timeline.test.ts @@ -244,6 +244,7 @@ function contextWindowUsageEvent({ }, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -273,6 +274,7 @@ function fileChangeItemEvent({ }, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -305,6 +307,7 @@ function toolCallItemEvent({ }, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -331,6 +334,7 @@ function imageViewItemEvent({ }, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -353,6 +357,7 @@ function planDeltaEvent({ delta: text, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -378,6 +383,7 @@ function planItemCompletedEvent({ }, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -394,6 +400,7 @@ function turnStartedEvent({ seq }: TurnStartedEventArgs): ThreadEventWithMeta { scope: turnScope("turn-1"), }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -416,6 +423,7 @@ function turnCompletedEvent({ ...(errorMessage ? { error: { message: errorMessage } } : {}), }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -449,6 +457,7 @@ function backgroundTaskStartedEvent({ item, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -476,6 +485,7 @@ function systemOperationEvent({ ...(metadata ? { metadata } : {}), }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -499,6 +509,7 @@ function systemErrorEvent({ ...(detail !== undefined ? { detail } : {}), }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -537,6 +548,7 @@ function systemProviderTurnWatchdogEvent({ firedAt: firedAt ?? seq, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -563,6 +575,7 @@ function providerErrorEvent({ ...(willRetry !== undefined ? { willRetry } : {}), }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -600,6 +613,7 @@ function permissionGrantLifecycleEvent({ }, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -644,6 +658,7 @@ function userQuestionLifecycleEvent({ }, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, diff --git a/packages/thread-view/test/completed-turn-grouping.test.ts b/packages/thread-view/test/completed-turn-grouping.test.ts index 8792d98470..670dc5ac03 100644 --- a/packages/thread-view/test/completed-turn-grouping.test.ts +++ b/packages/thread-view/test/completed-turn-grouping.test.ts @@ -45,6 +45,7 @@ interface UserMessageArgs extends MessageBaseArgs { function userMessage(args: UserMessageArgs): EventProjectionUserMessage { return { + actorHandle: null, ...messageBase(args), kind: "user", initiator: args.initiator ?? "user", diff --git a/packages/thread-view/test/goal-snapshot-extraction.test.ts b/packages/thread-view/test/goal-snapshot-extraction.test.ts index 361843b9ef..56d2f7214d 100644 --- a/packages/thread-view/test/goal-snapshot-extraction.test.ts +++ b/packages/thread-view/test/goal-snapshot-extraction.test.ts @@ -23,6 +23,7 @@ function goalUpdatedEvent({ timeUsedSeconds: 30, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq * 100, @@ -39,6 +40,7 @@ function goalClearedEvent(seq: number): ThreadEventWithMeta { scope: threadScope(), }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq * 100, diff --git a/packages/thread-view/test/model-fallback-extraction.test.ts b/packages/thread-view/test/model-fallback-extraction.test.ts index b2c8bbedc7..5a11281814 100644 --- a/packages/thread-view/test/model-fallback-extraction.test.ts +++ b/packages/thread-view/test/model-fallback-extraction.test.ts @@ -8,7 +8,12 @@ function event( ): ThreadEventWithMeta { return { event: value, - meta: { id: `event-${sequence}`, seq: sequence, createdAt: sequence * 10 }, + meta: { + id: `event-${sequence}`, + seq: sequence, + createdAt: sequence * 10, + actorHandle: null, + }, }; } diff --git a/packages/thread-view/test/timeline-progression.test.ts b/packages/thread-view/test/timeline-progression.test.ts index 32e7b2b5ae..5c71a2b642 100644 --- a/packages/thread-view/test/timeline-progression.test.ts +++ b/packages/thread-view/test/timeline-progression.test.ts @@ -61,6 +61,7 @@ function userRow(text: string): TimelineConversationRow { attachments: null, initiator: "user", senderThreadId: null, + actorHandle: null, systemMessageKind: "unlabeled", systemMessageSubject: null, turnRequest: { kind: "message", status: "accepted" }, @@ -334,6 +335,7 @@ describe("findTimelineFrontierRow", () => { attachments: null, initiator: "user", senderThreadId: null, + actorHandle: null, systemMessageKind: "unlabeled", systemMessageSubject: null, turnRequest: { kind: "steer", status: "pending" }, diff --git a/packages/thread-view/test/timeline-test-harness.ts b/packages/thread-view/test/timeline-test-harness.ts index 656637a37e..dc5d10c163 100644 --- a/packages/thread-view/test/timeline-test-harness.ts +++ b/packages/thread-view/test/timeline-test-harness.ts @@ -63,6 +63,7 @@ export interface TimelineEventFactoryDefaults { } export interface EventFactoryRowOptions { + actorHandle?: string | null; createdAt?: number; id?: string; seq?: number; @@ -451,6 +452,7 @@ export function createTimelineEventFactory( threadId: options?.threadId ?? defaults.threadId, seq, createdAt: options?.createdAt ?? seq, + actorHandle: options?.actorHandle ?? null, }; } diff --git a/packages/thread-view/test/todo-snapshot-extraction.test.ts b/packages/thread-view/test/todo-snapshot-extraction.test.ts index 7ac9e49d81..6530d27b75 100644 --- a/packages/thread-view/test/todo-snapshot-extraction.test.ts +++ b/packages/thread-view/test/todo-snapshot-extraction.test.ts @@ -58,6 +58,7 @@ function todoWriteEvent({ }, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -89,6 +90,7 @@ function taskToolEvent({ }, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -106,6 +108,7 @@ function turnPlanEvent({ plan, seq }: TurnPlanEventArgs): ThreadEventWithMeta { plan, }, meta: { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, @@ -128,7 +131,7 @@ function nonTodoToolCallEvent(seq: number): ThreadEventWithMeta { status: "completed", }, }, - meta: { id: `event-${seq}`, seq, createdAt: seq }, + meta: { id: `event-${seq}`, seq, createdAt: seq, actorHandle: null }, }; } diff --git a/packages/thread-view/test/tool-activity-projection.test.ts b/packages/thread-view/test/tool-activity-projection.test.ts index 2408092b92..a6299949aa 100644 --- a/packages/thread-view/test/tool-activity-projection.test.ts +++ b/packages/thread-view/test/tool-activity-projection.test.ts @@ -63,6 +63,7 @@ function createProjectionState(): ToolActivityProjectionState { function eventMeta(seq: number): EventMeta { return { + actorHandle: null, id: `event-${seq}`, seq, createdAt: seq, diff --git a/packages/thread-view/test/user-message-parsing.test.ts b/packages/thread-view/test/user-message-parsing.test.ts index a8b38c0f5a..da9795052c 100644 --- a/packages/thread-view/test/user-message-parsing.test.ts +++ b/packages/thread-view/test/user-message-parsing.test.ts @@ -95,6 +95,7 @@ function acceptedClientRequest( ): AcceptedClientRequest { return { meta: { + actorHandle: null, id: "event-accepted", seq: 2, createdAt: 2, diff --git a/tests/integration/fake/smoke/timeline-response.test.ts b/tests/integration/fake/smoke/timeline-response.test.ts index aa0a8b7d37..63fb573c2a 100644 --- a/tests/integration/fake/smoke/timeline-response.test.ts +++ b/tests/integration/fake/smoke/timeline-response.test.ts @@ -35,6 +35,7 @@ const USER_ROW = { attachments: null, initiator: "user", senderThreadId: null, + actorHandle: null, systemMessageKind: "unlabeled", systemMessageSubject: null, turnRequest: { kind: "message", status: "accepted" }, From 59cc824cb5b0340a7fb836adf23707c486fd916a Mon Sep 17 00:00:00 2001 From: Sawyer Hood Date: Sat, 18 Jul 2026 10:17:09 -0700 Subject: [PATCH 5/8] Multiplayer wave 3: app UI, members CLI/SDK, and owner-console member management WS5 (app): claimed-identity store (localStorage, remote-context-only prompt + settings section; desktop stays the silent local operator), identity attached at the single fetch choke point and as ?identity= on the ws URL, presence store fed by thread-presence/presence-summary broadcasts and reseeded from GET /api/v1/presence on (re)connect, viewer avatars in the thread header, typing indicator + throttled typing emit at the composer, sidebar presence dots with click-to-follow, and author chips on user messages that appear only when a thread has 2+ distinct human authors. Optimistic user rows stamp the sender's own handle. WS6 (surfaces): tunnel-client strips inbound x-bb-via-tunnel and stamps it on every re-issued request/upgrade, so member management can be owner-console- only; connect member endpoints also accept the server's own tunnel credential as owner-equivalent; local GET/POST/DELETE /api/v1/members proxy (rejects tunnel-origin requests, surfaces enrollment/handle/duplicate errors); SDK members + presence areas and a claimedIdentity client option; bb members list/add/remove CLI; guide chapter, bb-cli skill, and docs updated; bb-app public SDK facade gains the new areas. Co-Authored-By: Claude Fable 5 --- apps/app/src/App.tsx | 2 + .../dialogs/ClaimIdentityDialog.tsx | 107 ++++++ .../settings/IdentitySettingsSection.tsx | 83 +++++ .../src/components/settings/settings-nav.tsx | 7 + apps/app/src/components/sidebar/ThreadRow.tsx | 16 + .../thread/presence/Presence.stories.tsx | 88 +++++ .../thread/presence/PresenceAvatarRow.tsx | 100 ++++++ .../thread/presence/SidebarPresenceDots.tsx | 40 +++ .../presence/ThreadPresenceIndicators.tsx | 40 +++ .../thread/presence/TypingIndicator.tsx | 34 ++ .../timeline/ConversationMessageContent.tsx | 29 ++ .../GeneratedConversationMessage.stories.tsx | 8 + .../GeneratedConversationMessage.test.tsx | 4 + .../thread/timeline/ThreadTimelineRows.tsx | 45 +++ .../timeline/UserMessageMarkdown.stories.tsx | 2 + .../timeline/rows/UserMessage.stories.tsx | 32 ++ .../timeline/timeline-message-authors.test.ts | 43 +++ .../ui/markdown-message-directives.test.tsx | 2 + .../thread-runtime-cache-owner.ts | 5 +- apps/app/src/hooks/useTypingEmitter.ts | 88 +++++ apps/app/src/lib/app-surface.ts | 8 + .../src/lib/claimed-identity-store.test.ts | 64 ++++ apps/app/src/lib/claimed-identity-store.ts | 177 ++++++++++ apps/app/src/lib/presence-store.test.ts | 63 ++++ apps/app/src/lib/presence-store.ts | 161 +++++++++ apps/app/src/lib/ws.presence.test.ts | 70 ++++ apps/app/src/lib/ws.ts | 67 +++- apps/app/src/views/SettingsView.tsx | 3 + .../thread-detail/ThreadDetailHeader.tsx | 4 + .../thread-detail/ThreadDetailPromptArea.tsx | 8 + .../views/thread-detail/ThreadDetailView.tsx | 2 + .../__tests__/command-output/members.test.ts | 96 ++++++ .../__tests__/json-flag-enforcement.test.ts | 2 + apps/cli/src/client.ts | 5 + apps/cli/src/commands/members.ts | 82 +++++ apps/cli/src/index.ts | 2 + apps/connect/src/members.test.ts | 102 +++++- apps/connect/src/members.ts | 71 +++- apps/connect/src/servers.test.ts | 30 +- apps/connect/src/servers.ts | 5 +- apps/server/src/routes/members.ts | 311 ++++++++++++++++++ apps/server/src/server.ts | 2 + .../skills/builtin-skills/bb-cli/SKILL.md | 15 + .../server/test/public/public-members.test.ts | 95 ++++++ docs/agent-api-cli-parity.md | 39 +++ docs/plugin-api-and-sdk-reference.md | 98 +++--- packages/bb-app/src/public-sdk.ts | 4 + .../bundled-types/bb-plugin-sdk.d.ts | 165 ++++++---- packages/sdk/src/areas/members.ts | 42 +++ packages/sdk/src/areas/presence.ts | 16 + packages/sdk/src/browser.ts | 3 + packages/sdk/src/core.ts | 6 + packages/sdk/src/node.ts | 3 + packages/sdk/src/public-types.ts | 2 + packages/sdk/src/realtime-url.ts | 49 +-- packages/sdk/src/transport-http.ts | 28 +- packages/sdk/src/transport.ts | 8 +- packages/sdk/test/public-types.test.ts | 2 + packages/sdk/test/sdk.test.ts | 109 +++++- packages/server-contract/src/api-types.ts | 1 + packages/server-contract/src/api/members.ts | 26 ++ packages/server-contract/src/public-api.ts | 31 ++ .../src/generated/plugin-sdk-dts.generated.ts | 2 +- .../src/generated/templates.generated.ts | 2 +- .../src/templates/bb-guide-machines.md | 19 ++ packages/tunnel-client/src/headers.ts | 8 + packages/tunnel-client/src/index.ts | 1 + packages/tunnel-client/src/session.ts | 2 + packages/tunnel-client/test/headers.test.ts | 37 +++ 69 files changed, 2763 insertions(+), 160 deletions(-) create mode 100644 apps/app/src/components/dialogs/ClaimIdentityDialog.tsx create mode 100644 apps/app/src/components/settings/IdentitySettingsSection.tsx create mode 100644 apps/app/src/components/thread/presence/Presence.stories.tsx create mode 100644 apps/app/src/components/thread/presence/PresenceAvatarRow.tsx create mode 100644 apps/app/src/components/thread/presence/SidebarPresenceDots.tsx create mode 100644 apps/app/src/components/thread/presence/ThreadPresenceIndicators.tsx create mode 100644 apps/app/src/components/thread/presence/TypingIndicator.tsx create mode 100644 apps/app/src/components/thread/timeline/timeline-message-authors.test.ts create mode 100644 apps/app/src/hooks/useTypingEmitter.ts create mode 100644 apps/app/src/lib/claimed-identity-store.test.ts create mode 100644 apps/app/src/lib/claimed-identity-store.ts create mode 100644 apps/app/src/lib/presence-store.test.ts create mode 100644 apps/app/src/lib/presence-store.ts create mode 100644 apps/app/src/lib/ws.presence.test.ts create mode 100644 apps/cli/src/__tests__/command-output/members.test.ts create mode 100644 apps/cli/src/commands/members.ts create mode 100644 apps/server/src/routes/members.ts create mode 100644 apps/server/test/public/public-members.test.ts create mode 100644 packages/sdk/src/areas/members.ts create mode 100644 packages/sdk/src/areas/presence.ts create mode 100644 packages/server-contract/src/api/members.ts create mode 100644 packages/tunnel-client/test/headers.test.ts diff --git a/apps/app/src/App.tsx b/apps/app/src/App.tsx index 448ded24a9..7df81d754d 100644 --- a/apps/app/src/App.tsx +++ b/apps/app/src/App.tsx @@ -4,6 +4,7 @@ import { AppLayout } from "./components/layout/AppLayout"; import { AuthCallbackView } from "./views/AuthCallbackView"; import { QuickCreateProjectProvider } from "./hooks/useQuickCreateProject"; import { ProviderCliHealthToasts } from "./components/provider-cli/ProviderCliHealthToasts"; +import { ClaimIdentityDialog } from "./components/dialogs/ClaimIdentityDialog"; import { RouteNavigationProvider } from "./components/ui/app-route-anchor"; import { useAppTheme } from "./hooks/useAppTheme"; import { useFaviconColorSync } from "./lib/favicon-color-preference"; @@ -96,6 +97,7 @@ export function App() { + { + markPromptDismissed(); + setDismissed(true); + }; + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + if (setClaimedDisplayName(displayName) !== null) { + dismiss(); + } + }; + + return ( + (next ? undefined : dismiss())}> + + + Who's here? + + You're viewing this bb remotely. Add a display name so your + messages and presence are attributed to you — everyone with access + can see it. + + +
+
+ setDisplayName(event.target.value)} + /> + {handle.length > 0 ? ( +

+ You'll appear as @{handle} +

+ ) : null} +
+ + + + +
+
+
+ ); +} diff --git a/apps/app/src/components/settings/IdentitySettingsSection.tsx b/apps/app/src/components/settings/IdentitySettingsSection.tsx new file mode 100644 index 0000000000..a742048948 --- /dev/null +++ b/apps/app/src/components/settings/IdentitySettingsSection.tsx @@ -0,0 +1,83 @@ +import { useEffect, useState, type FormEvent } from "react"; +import { normalizeHandle } from "@bb/domain"; +import { Button } from "@bb/shared-ui/button"; +import { Input } from "@bb/shared-ui/input"; +import { SettingsSection } from "@/components/ui/settings-section"; +import { + clearClaimedIdentity, + setClaimedDisplayName, + useClaimedIdentity, +} from "@/lib/claimed-identity-store"; + +/** + * Remote-session identity editor: the claimed display name/handle this browser + * attaches to its requests for attribution and presence. Only offered in the + * settings nav for remote sessions (desktop/localhost run as the local + * operator and send no identity). + */ +export function IdentitySettingsSection() { + const identity = useClaimedIdentity(); + const [displayName, setDisplayName] = useState(identity?.displayName ?? ""); + // Re-seed the field when the identity changes elsewhere (first-load dialog, + // another tab via the storage event). + useEffect(() => { + setDisplayName(identity?.displayName ?? ""); + }, [identity?.displayName]); + const handle = normalizeHandle(displayName); + const isDirty = displayName.trim() !== (identity?.displayName ?? ""); + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + setClaimedDisplayName(displayName); + }; + + return ( + +
+
+ + setDisplayName(event.target.value)} + /> +

+ {handle.length > 0 + ? `You appear as @${handle}` + : "No identity claimed — your actions show as the machine owner."} +

+
+
+ + {identity !== null ? ( + + ) : null} +
+
+
+ ); +} diff --git a/apps/app/src/components/settings/settings-nav.tsx b/apps/app/src/components/settings/settings-nav.tsx index bd036d9814..a4c1312182 100644 --- a/apps/app/src/components/settings/settings-nav.tsx +++ b/apps/app/src/components/settings/settings-nav.tsx @@ -8,6 +8,7 @@ import { useSystemConfig } from "@/hooks/queries/system-queries"; import { useHostDaemon } from "@/hooks/useHostDaemon"; import { usePluginSlots } from "@/lib/plugin-slots"; import { PluginIcon } from "@/components/plugin/PluginIcon"; +import { isRemoteAppContext } from "@/lib/claimed-identity-store"; import { SETTINGS_PLUGIN_ROUTE_PATH, SETTINGS_PROVIDER_ROUTE_PATH, @@ -21,6 +22,7 @@ import { */ export const SETTINGS_NAV_SECTIONS = [ { icon: "Settings", id: "general", label: "General" }, + { icon: "UserRound", id: "identity", label: "Identity" }, { icon: "Palette", id: "appearance", label: "Appearance" }, { icon: "SlidersHorizontal", id: "keyboard", label: "Keyboard" }, { icon: "ChartColumn", id: "usage", label: "Usage limits" }, @@ -122,6 +124,11 @@ export function useSettingsNavState(): SettingsNavState { if (section.id === "files") { return hasDaemon || fileOpeners.length > 0; } + if (section.id === "identity") { + // Claimed identity only applies to remote sessions; desktop/localhost + // run as the local operator with no identity to edit. + return isRemoteAppContext(); + } if (section.id === "plugins") { return pluginsEnabled; } diff --git a/apps/app/src/components/sidebar/ThreadRow.tsx b/apps/app/src/components/sidebar/ThreadRow.tsx index 550dedaa52..01bd280f2c 100644 --- a/apps/app/src/components/sidebar/ThreadRow.tsx +++ b/apps/app/src/components/sidebar/ThreadRow.tsx @@ -1,6 +1,7 @@ import { memo, useCallback, + useMemo, useState, type CSSProperties, type MouseEventHandler, @@ -67,6 +68,9 @@ import { useThreadSplitsEnabled } from "@/hooks/useThreadSplitsEnabled"; import { useThreadRowSplitDrag } from "./useThreadRowSplitDrag"; import { APP_COMMAND_SHORTCUT_HINT_CLASS } from "@/components/commands/AppCommandShortcutHint"; import { useThreadTitleDisplayText } from "@/components/thread/ThreadTitleMentions"; +import { SidebarPresenceDots } from "@/components/thread/presence/SidebarPresenceDots"; +import { useClaimedIdentity } from "@/lib/claimed-identity-store"; +import { useThreadPresenceSummaryHandles } from "@/lib/presence-store"; interface ThreadRowBaseOptions { depth: number; @@ -495,6 +499,17 @@ function ThreadRowComponent({ getThreadConversationCollapsedAtom(thread.id), ); const shortcut = useSidebarThreadShortcut(thread.id); + // Other collaborators currently viewing this thread (presence summary minus + // our own claimed handle); clicking a dot navigates via the row's own link. + const presenceHandles = useThreadPresenceSummaryHandles(thread.id); + const ownHandle = useClaimedIdentity()?.handle ?? null; + const otherPresenceHandles = useMemo( + () => + ownHandle === null + ? presenceHandles + : presenceHandles.filter((handle) => handle !== ownHandle), + [presenceHandles, ownHandle], + ); const showActive = isActive; const hasPendingInteraction = thread.hasPendingInteraction; const threadRuntimeBusy = @@ -651,6 +666,7 @@ function ThreadRowComponent({ ) : null} + {splitIndicator.miniMap ? ( + + + + + + + + + + + + + + + + + ); +} + +export function SidebarDots() { + return ( + + + + + + + + + ); +} + +export function Typing() { + return ( + + + + + + + + + + + + + + + ); +} diff --git a/apps/app/src/components/thread/presence/PresenceAvatarRow.tsx b/apps/app/src/components/thread/presence/PresenceAvatarRow.tsx new file mode 100644 index 0000000000..190a95b2ff --- /dev/null +++ b/apps/app/src/components/thread/presence/PresenceAvatarRow.tsx @@ -0,0 +1,100 @@ +import type { PresenceViewer } from "@bb/server-contract"; +import { cn } from "@bb/shared-ui/lib/utils"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@bb/shared-ui/tooltip"; + +const MAX_VISIBLE_AVATARS = 4; + +export type PresenceAvatarSize = "sm" | "md"; + +interface PresenceAvatarRowProps { + viewers: readonly PresenceViewer[]; + size?: PresenceAvatarSize; +} + +interface PresenceAvatarProps { + viewer: PresenceViewer; + size: PresenceAvatarSize; +} + +function avatarSizeClass(size: PresenceAvatarSize): string { + return size === "md" ? "size-5 text-[10px]" : "size-4 text-[9px]"; +} + +export function presenceInitials(displayName: string): string { + const words = displayName.trim().split(/\s+/u).filter(Boolean); + const first = words[0]?.[0] ?? "?"; + const second = words.length > 1 ? (words.at(-1)?.[0] ?? "") : ""; + return `${first}${second}`.toUpperCase(); +} + +// A viewer with an avatar renders the image; without one, initials on a +// recessed surface (per the claimed-identity contract, imageUrl null = no +// avatar, render initials). +function PresenceAvatar({ viewer, size }: PresenceAvatarProps) { + return ( + + + + {viewer.imageUrl === null ? ( + presenceInitials(viewer.displayName) + ) : ( + + )} + + + {viewer.displayName} + + ); +} + +/** + * Overlapping avatar row of the collaborators currently viewing a thread. + * Callers pre-filter the roster (e.g. exclude the local viewer); renders + * nothing when it is empty. + */ +export function PresenceAvatarRow({ + viewers, + size = "md", +}: PresenceAvatarRowProps) { + if (viewers.length === 0) { + return null; + } + const visible = viewers.slice(0, MAX_VISIBLE_AVATARS); + const overflow = viewers.length - visible.length; + return ( + + {visible.map((viewer) => ( + + ))} + {overflow > 0 ? ( + + +{overflow} + + ) : null} + + ); +} diff --git a/apps/app/src/components/thread/presence/SidebarPresenceDots.tsx b/apps/app/src/components/thread/presence/SidebarPresenceDots.tsx new file mode 100644 index 0000000000..c55f3636b7 --- /dev/null +++ b/apps/app/src/components/thread/presence/SidebarPresenceDots.tsx @@ -0,0 +1,40 @@ +const MAX_VISIBLE_DOTS = 3; + +/** + * Compact viewer markers for sidebar thread rows: one initial-dot per remote + * viewer handle from the presence summary. Purely decorative — the row's own + * link handles navigation (clicking a dot follows/jumps to the thread). + */ +export function SidebarPresenceDots({ + handles, +}: { + handles: readonly string[]; +}) { + if (handles.length === 0) { + return null; + } + const visible = handles.slice(0, MAX_VISIBLE_DOTS); + const overflow = handles.length - visible.length; + return ( + `@${handle}`).join(", ")}`} + className="pointer-events-none inline-flex shrink-0 items-center -space-x-0.5" + > + {visible.map((handle) => ( + + {handle[0] ?? "?"} + + ))} + {overflow > 0 ? ( + + +{overflow} + + ) : null} + + ); +} diff --git a/apps/app/src/components/thread/presence/ThreadPresenceIndicators.tsx b/apps/app/src/components/thread/presence/ThreadPresenceIndicators.tsx new file mode 100644 index 0000000000..5abe8aaf1c --- /dev/null +++ b/apps/app/src/components/thread/presence/ThreadPresenceIndicators.tsx @@ -0,0 +1,40 @@ +import { useMemo } from "react"; +import type { PresenceViewer } from "@bb/server-contract"; +import { useClaimedIdentity } from "@/lib/claimed-identity-store"; +import { useThreadPresenceViewers } from "@/lib/presence-store"; +import { PresenceAvatarRow } from "./PresenceAvatarRow"; +import { TypingIndicator } from "./TypingIndicator"; + +/** + * The other people looking at this thread: the live roster minus the local + * viewer's own handle. Without a claimed identity the local viewer is the + * anonymous local operator, which the server never includes in rosters, so + * nothing needs excluding. + */ +function useOtherThreadViewers(threadId: string): readonly PresenceViewer[] { + const viewers = useThreadPresenceViewers(threadId); + const ownHandle = useClaimedIdentity()?.handle ?? null; + return useMemo( + () => + ownHandle === null + ? viewers + : viewers.filter((viewer) => viewer.handle !== ownHandle), + [viewers, ownHandle], + ); +} + +/** Thread-header avatar row of the other current viewers. */ +export function ThreadPresenceHeaderAvatars({ threadId }: { threadId: string }) { + const others = useOtherThreadViewers(threadId); + return ; +} + +/** "@alice is typing…" line for other viewers currently typing. */ +export function ThreadTypingIndicator({ threadId }: { threadId: string }) { + const others = useOtherThreadViewers(threadId); + const typingHandles = useMemo( + () => others.filter((viewer) => viewer.typing).map((v) => v.handle), + [others], + ); + return ; +} diff --git a/apps/app/src/components/thread/presence/TypingIndicator.tsx b/apps/app/src/components/thread/presence/TypingIndicator.tsx new file mode 100644 index 0000000000..99139ce22b --- /dev/null +++ b/apps/app/src/components/thread/presence/TypingIndicator.tsx @@ -0,0 +1,34 @@ +export function typingIndicatorLabel( + handles: readonly string[], +): string | null { + if (handles.length === 0) { + return null; + } + if (handles.length === 1) { + return `@${handles[0]} is typing…`; + } + if (handles.length === 2) { + return `@${handles[0]} and @${handles[1]} are typing…`; + } + return `@${handles[0]} and ${handles.length - 1} others are typing…`; +} + +/** + * One-line composer-adjacent typing readout for other collaborators. Renders + * nothing when no one else is typing. + */ +export function TypingIndicator({ handles }: { handles: readonly string[] }) { + const label = typingIndicatorLabel(handles); + if (label === null) { + return null; + } + return ( +

+ {label} +

+ ); +} diff --git a/apps/app/src/components/thread/timeline/ConversationMessageContent.tsx b/apps/app/src/components/thread/timeline/ConversationMessageContent.tsx index 581e17490e..f5e927878c 100644 --- a/apps/app/src/components/thread/timeline/ConversationMessageContent.tsx +++ b/apps/app/src/components/thread/timeline/ConversationMessageContent.tsx @@ -69,6 +69,13 @@ interface ConversationMessageContentBaseProps { export interface ConversationMessageContentUserProps extends ConversationMessageContentBaseProps { role: "user"; + /** Claimed handle of the human who sent this row; null = unattributed. */ + actorHandle: string | null; + /** + * True when the loaded timeline has 2+ distinct authors. Gates the author + * chip so single-author threads render exactly as before multiplayer. + */ + showAuthor: boolean; /** Mobile presentation for the regular user message's action footer. */ mobileActionDisplay?: "inline" | "overflow"; /** @@ -169,9 +176,11 @@ export type ConversationMessageContentProps = | ConversationMessageContentAssistantProps; interface UserConversationMessageProps { + actorHandle: string | null; addToChatAttachments: readonly PromptDraftAttachment[]; attachmentItems: ConversationAttachmentItems; childOrigin: ThreadChildOrigin | null; + showAuthor: boolean; initiator: TimelineUserConversationRow["initiator"]; mentions: readonly PromptTextMention[]; mobileActionDisplay: "inline" | "overflow"; @@ -352,10 +361,12 @@ function buildAddToChatAttachments( } function UserConversationMessage({ + actorHandle, addToChatAttachments, attachmentItems, childOrigin, initiator, + showAuthor, mentions, mobileActionDisplay, onAddToChat, @@ -440,10 +451,26 @@ function UserConversationMessage({ const mutePrefixLength = computeMutedPrefixLength(initiator, text); const messageText = text.trim(); const requestLabel = turnRequestLabel(turnRequest); + // Author chip only in genuinely multi-author threads (2+ distinct handles + // loaded) and only for attributed rows — legacy rows carry a null handle. + const authorChipHandle = showAuthor && actorHandle !== null ? actorHandle : null; return (
+ {authorChipHandle !== null ? ( +
+ + {authorChipHandle[0] ?? "?"} + + + @{authorChipHandle} + +
+ ) : null} {requestLabel ? (
; + /** True when 2+ distinct authors are loaded; user rows then show author chips. */ + showMessageAuthors: boolean; themeType: ThreadTimelineTheme; threadId: string | undefined; workspaceRootPath: string | undefined; @@ -692,6 +694,40 @@ function isForkSeedAnchorRow(row: TimelineConversationViewRow): boolean { ); } +/** + * Whether the loaded timeline shows more than one distinct human author + * (2+ distinct non-null `actorHandle`s on user rows). Single-author threads + * stay chip-free so the classic solo layout is untouched; the moment a second + * collaborator's message loads, every attributed user row gains its author. + */ +export function timelineHasMultipleMessageAuthors( + rows: readonly ThreadTimelineViewRow[], +): boolean { + const handles = new Set(); + + const visitRows = (candidateRows: readonly ThreadTimelineViewRow[]): boolean => { + for (const row of candidateRows) { + if (row.kind === "conversation") { + if (row.role === "user" && row.actorHandle !== null) { + handles.add(row.actorHandle); + if (handles.size >= 2) { + return true; + } + } + continue; + } + if (row.kind === "turn" && row.children !== null) { + if (visitRows(row.children)) { + return true; + } + } + } + return false; + }; + + return visitRows(rows); +} + /** * Finds the final assistant row whose action bar is available in the rendered * timeline. Completed turn details and delegated-agent output intentionally do @@ -792,6 +828,7 @@ function ConversationRow({ resolveSegmentLinkHref, resolveUserAttachmentImageSrc, senderThreadMetadataById, + showMessageAuthors, workspaceRootPath, } = useTimelineRendererStaticContext(); if (row.role === "user") { @@ -805,9 +842,11 @@ function ConversationRow({ const childOrigin = isForkSeedAnchorRow(row) ? threadChildOrigin : null; return ( timelineHasMultipleMessageAuthors(rows), + [rows], + ); // Single plugin-slot subscription for the whole timeline; messages read the // stable registry from context instead of each opening a store subscription. // Provide getServerSnapshot so renderToStaticMarkup / SSR tests work. @@ -1859,6 +1902,7 @@ function ThreadTimelineRowsForTimelineView(props: ThreadTimelineRowsProps) { resolveSegmentLinkHref, resolveUserAttachmentImageSrc: props.resolveUserAttachmentImageSrc, senderThreadMetadataById, + showMessageAuthors, themeType, threadId: props.threadId, workspaceRootPath: props.workspaceRootPath, @@ -1883,6 +1927,7 @@ function ThreadTimelineRowsForTimelineView(props: ThreadTimelineRowsProps) { resolveSegmentLinkHref, props.resolveUserAttachmentImageSrc, senderThreadMetadataById, + showMessageAuthors, props.threadId, props.workspaceRootPath, themeType, diff --git a/apps/app/src/components/thread/timeline/UserMessageMarkdown.stories.tsx b/apps/app/src/components/thread/timeline/UserMessageMarkdown.stories.tsx index f9e22def74..f294fc1c2a 100644 --- a/apps/app/src/components/thread/timeline/UserMessageMarkdown.stories.tsx +++ b/apps/app/src/components/thread/timeline/UserMessageMarkdown.stories.tsx @@ -72,7 +72,9 @@ function UserMessage({ return (
{ + it("stays single-author for null-handle (legacy/local) rows", () => { + expect( + timelineHasMultipleMessageAuthors([userRow(1, null), userRow(2, null)]), + ).toBe(false); + }); + + it("stays single-author when every attributed row shares one handle", () => { + expect( + timelineHasMultipleMessageAuthors([ + userRow(1, "alice"), + userRow(2, "alice"), + userRow(3, null), + ]), + ).toBe(false); + }); + + it("flips on the second distinct handle", () => { + expect( + timelineHasMultipleMessageAuthors([ + userRow(1, "alice"), + userRow(2, null), + userRow(3, "bob"), + ]), + ).toBe(true); + }); +}); diff --git a/apps/app/src/components/ui/markdown-message-directives.test.tsx b/apps/app/src/components/ui/markdown-message-directives.test.tsx index 103e59e918..38dfd27000 100644 --- a/apps/app/src/components/ui/markdown-message-directives.test.tsx +++ b/apps/app/src/components/ui/markdown-message-directives.test.tsx @@ -507,7 +507,9 @@ describe("ConversationMessageContent assistant directives", () => { (null); + const isFirstRunForThreadRef = useRef(true); + + useEffect(() => { + isFirstRunForThreadRef.current = true; + return () => { + if (idleTimerRef.current !== null) { + window.clearTimeout(idleTimerRef.current); + idleTimerRef.current = null; + } + if (isTypingRef.current) { + isTypingRef.current = false; + wsManager.sendTyping(threadId, false); + } + lastSentAtRef.current = 0; + }; + }, [threadId]); + + useEffect(() => { + // Mounting with a restored draft is not typing — only subsequent edits are. + if (isFirstRunForThreadRef.current) { + isFirstRunForThreadRef.current = false; + return; + } + if (!enabled) { + return; + } + + if (draftText.length === 0) { + if (idleTimerRef.current !== null) { + window.clearTimeout(idleTimerRef.current); + idleTimerRef.current = null; + } + if (isTypingRef.current) { + isTypingRef.current = false; + wsManager.sendTyping(threadId, false); + } + return; + } + + const now = Date.now(); + if (!isTypingRef.current || now - lastSentAtRef.current >= TYPING_REFRESH_MS) { + isTypingRef.current = true; + lastSentAtRef.current = now; + wsManager.sendTyping(threadId, true); + } + + if (idleTimerRef.current !== null) { + window.clearTimeout(idleTimerRef.current); + } + idleTimerRef.current = window.setTimeout(() => { + idleTimerRef.current = null; + if (isTypingRef.current) { + isTypingRef.current = false; + wsManager.sendTyping(threadId, false); + } + }, TYPING_IDLE_TIMEOUT_MS); + }, [draftText, enabled, threadId]); +} diff --git a/apps/app/src/lib/app-surface.ts b/apps/app/src/lib/app-surface.ts index ce43066ab2..e140ee2674 100644 --- a/apps/app/src/lib/app-surface.ts +++ b/apps/app/src/lib/app-surface.ts @@ -4,6 +4,8 @@ import { APP_SURFACE_WEB, type AppSurface, } from "@bb/config/app-surface"; +import { CLAIMED_IDENTITY_HEADER } from "@bb/domain"; +import { getClaimedIdentityHeaderValue } from "./claimed-identity-store"; export function getAppSurface(): AppSurface { if (typeof window !== "undefined" && window.bbDesktop !== undefined) { @@ -15,6 +17,12 @@ export function getAppSurface(): AppSurface { export function appSurfaceRequestInit(init?: RequestInit): RequestInit { const headers = new Headers(init?.headers); headers.set(APP_SURFACE_HEADER_NAME, getAppSurface()); + // Remote sessions self-assert who they are on every request; absent identity + // (desktop/localhost) falls back to the server's local-operator default. + const claimedIdentity = getClaimedIdentityHeaderValue(); + if (claimedIdentity !== null) { + headers.set(CLAIMED_IDENTITY_HEADER, claimedIdentity); + } return { ...init, headers, diff --git a/apps/app/src/lib/claimed-identity-store.test.ts b/apps/app/src/lib/claimed-identity-store.test.ts new file mode 100644 index 0000000000..c9f16ee61b --- /dev/null +++ b/apps/app/src/lib/claimed-identity-store.test.ts @@ -0,0 +1,64 @@ +// @vitest-environment jsdom +import { afterEach, describe, expect, it } from "vitest"; +import { + clearClaimedIdentity, + getClaimedIdentity, + isRemoteAppContext, + resetClaimedIdentityStoreForTest, + setClaimedDisplayName, +} from "./claimed-identity-store"; + +afterEach(() => { + localStorage.clear(); + resetClaimedIdentityStoreForTest(); +}); + +describe("claimed identity store", () => { + // jsdom serves the suite from localhost, which is exactly the context that + // must never claim an identity — desktop/localhost run as the local operator. + it("treats the localhost origin as non-remote and suppresses any identity", () => { + expect(isRemoteAppContext()).toBe(false); + setClaimedDisplayName("Alice Chen"); + expect(getClaimedIdentity()).toBeNull(); + }); + + it("normalizes the display name into the stored handle", () => { + const identity = setClaimedDisplayName(" Alice Chen "); + expect(identity).not.toBeNull(); + expect(identity?.displayName).toBe("Alice Chen"); + expect(identity?.handle).toBe("alice chen"); + expect(identity?.imageUrl).toBeNull(); + expect(identity?.clientId.length).toBeGreaterThan(0); + }); + + it("rejects names that normalize to nothing", () => { + expect(setClaimedDisplayName(" ")).toBeNull(); + }); + + it("keeps the same clientId across identity changes", () => { + const first = setClaimedDisplayName("Alice"); + const second = setClaimedDisplayName("Alice Cooper"); + expect(second?.clientId).toBe(first?.clientId); + }); + + it("persists the identity to storage and reloads it", () => { + setClaimedDisplayName("Alice"); + resetClaimedIdentityStoreForTest(); + // Storage round-trip: stored value survives a module-state reset. The + // localhost gate still hides it from getClaimedIdentity, so assert the raw + // persisted record instead. + const raw = localStorage.getItem("bb.claimedIdentity"); + expect(raw).not.toBeNull(); + expect(JSON.parse(raw ?? "{}")).toMatchObject({ + handle: "alice", + displayName: "Alice", + imageUrl: null, + }); + }); + + it("clears the stored identity", () => { + setClaimedDisplayName("Alice"); + clearClaimedIdentity(); + expect(localStorage.getItem("bb.claimedIdentity")).toBeNull(); + }); +}); diff --git a/apps/app/src/lib/claimed-identity-store.ts b/apps/app/src/lib/claimed-identity-store.ts new file mode 100644 index 0000000000..64603b48d9 --- /dev/null +++ b/apps/app/src/lib/claimed-identity-store.ts @@ -0,0 +1,177 @@ +import { useSyncExternalStore } from "react"; +import { + claimedIdentitySchema, + encodeClaimedIdentityHeader, + normalizeHandle, + type ClaimedIdentity, +} from "@bb/domain"; + +/** + * Client-side owner of the CLAIMED multiplayer identity (see + * @bb/domain/claimed-identity: self-asserted, attribution-only, never used for + * authorization). The desktop shell and localhost browsers send no identity at + * all — the server's local-operator default covers the single-player case — + * so the store only activates for a remote web origin. + */ +const CLAIMED_IDENTITY_STORAGE_KEY = "bb.claimedIdentity"; +const CLIENT_ID_STORAGE_KEY = "bb.claimedIdentity.clientId"; + +/** + * True when this app instance is a remote browser session: not the desktop + * shell (`window.bbDesktop`, same signal as getAppSurface) and not a localhost + * origin. Only remote sessions claim an identity. + */ +export function isRemoteAppContext(): boolean { + if (typeof window === "undefined" || window.bbDesktop !== undefined) { + return false; + } + const hostname = window.location.hostname; + return ( + hostname !== "localhost" && + hostname !== "127.0.0.1" && + hostname !== "[::1]" && + hostname !== "::1" + ); +} + +function readStorage(key: string): string | null { + try { + return localStorage.getItem(key); + } catch { + return null; + } +} + +function writeStorage(key: string, value: string | null): void { + try { + if (value === null) { + localStorage.removeItem(key); + } else { + localStorage.setItem(key, value); + } + } catch { + // Best-effort persistence; private-mode/quota failures degrade to a + // per-session identity. + } +} + +let cachedClientId: string | null = null; + +/** Per-device presence-bookkeeping hint; generated once and persisted. */ +function getOrCreateClientId(): string { + if (cachedClientId !== null) { + return cachedClientId; + } + const stored = readStorage(CLIENT_ID_STORAGE_KEY); + if (stored !== null && stored.length > 0 && stored.length <= 64) { + cachedClientId = stored; + return stored; + } + const created = crypto.randomUUID(); + writeStorage(CLIENT_ID_STORAGE_KEY, created); + cachedClientId = created; + return created; +} + +function readStoredIdentity(): ClaimedIdentity | null { + const raw = readStorage(CLAIMED_IDENTITY_STORAGE_KEY); + if (raw === null) { + return null; + } + let parsed: unknown; + try { + parsed = JSON.parse(raw); + } catch { + return null; + } + const result = claimedIdentitySchema.safeParse(parsed); + if (!result.success) { + return null; + } + const handle = normalizeHandle(result.data.handle); + if (handle.length === 0) { + return null; + } + return { ...result.data, handle }; +} + +let currentIdentity: ClaimedIdentity | null = readStoredIdentity(); +const listeners = new Set<() => void>(); + +function notify(): void { + for (const listener of listeners) { + listener(); + } +} + +/** + * The active claimed identity, or null when none applies. Always null outside + * a remote app context so desktop/localhost requests carry no identity even if + * a stale stored value exists (e.g. a copied browser profile). + */ +export function getClaimedIdentity(): ClaimedIdentity | null { + return isRemoteAppContext() ? currentIdentity : null; +} + +/** Encoded x-bb-claimed-identity value, or null when no identity applies. */ +export function getClaimedIdentityHeaderValue(): string | null { + const identity = getClaimedIdentity(); + return identity === null ? null : encodeClaimedIdentityHeader(identity); +} + +/** + * Claims an identity from a freeform display name (handle derived via + * normalizeHandle). Returns the stored identity, or null when the name + * normalizes to nothing. + */ +export function setClaimedDisplayName( + displayName: string, +): ClaimedIdentity | null { + const trimmed = displayName.trim().slice(0, 128); + const handle = normalizeHandle(trimmed).slice(0, 64); + if (trimmed.length === 0 || handle.length === 0) { + return null; + } + const identity: ClaimedIdentity = { + handle, + displayName: trimmed, + imageUrl: null, + clientId: getOrCreateClientId(), + }; + currentIdentity = identity; + writeStorage(CLAIMED_IDENTITY_STORAGE_KEY, JSON.stringify(identity)); + notify(); + return identity; +} + +export function clearClaimedIdentity(): void { + if (currentIdentity === null) { + return; + } + currentIdentity = null; + writeStorage(CLAIMED_IDENTITY_STORAGE_KEY, null); + notify(); +} + +export function subscribeClaimedIdentity(listener: () => void): () => void { + listeners.add(listener); + return () => { + listeners.delete(listener); + }; +} + +/** Reactive claimed identity (null when absent or not a remote context). */ +export function useClaimedIdentity(): ClaimedIdentity | null { + return useSyncExternalStore( + subscribeClaimedIdentity, + getClaimedIdentity, + () => null, + ); +} + +/** Test-only: reset module state so each test starts from storage. */ +export function resetClaimedIdentityStoreForTest(): void { + cachedClientId = null; + currentIdentity = readStoredIdentity(); + notify(); +} diff --git a/apps/app/src/lib/presence-store.test.ts b/apps/app/src/lib/presence-store.test.ts new file mode 100644 index 0000000000..2c9249d644 --- /dev/null +++ b/apps/app/src/lib/presence-store.test.ts @@ -0,0 +1,63 @@ +import { describe, expect, it } from "vitest"; +import type { PresenceViewer } from "@bb/server-contract"; +import { PresenceStore } from "./presence-store"; + +function viewer(handle: string, typing = false): PresenceViewer { + return { handle, displayName: handle, imageUrl: null, typing }; +} + +describe("PresenceStore", () => { + it("replaces a thread roster and removes it when the roster empties", () => { + const store = new PresenceStore(); + store.setThreadViewers("thr_1", [viewer("alice"), viewer("bob")]); + expect(store.getThreadViewers("thr_1").map((v) => v.handle)).toEqual([ + "alice", + "bob", + ]); + + store.setThreadViewers("thr_1", [viewer("alice")]); + expect(store.getThreadViewers("thr_1").map((v) => v.handle)).toEqual([ + "alice", + ]); + + store.setThreadViewers("thr_1", []); + expect(store.getThreadViewers("thr_1")).toEqual([]); + }); + + it("patches the summary partially: merge entries, empty array removes", () => { + const store = new PresenceStore(); + store.patchSummary({ thr_1: ["alice"], thr_2: ["bob"] }); + // A later partial patch must not disturb untouched threads. + store.patchSummary({ thr_2: ["bob", "carol"] }); + expect(store.getSummaryHandles("thr_1")).toEqual(["alice"]); + expect(store.getSummaryHandles("thr_2")).toEqual(["bob", "carol"]); + + store.patchSummary({ thr_1: [] }); + expect(store.getSummaryHandles("thr_1")).toEqual([]); + expect(store.getSummaryHandles("thr_2")).toEqual(["bob", "carol"]); + }); + + it("snapshot replace flushes rosters that went stale while disconnected", () => { + const store = new PresenceStore(); + store.setThreadViewers("thr_stale", [viewer("alice")]); + store.patchSummary({ thr_stale: ["alice"] }); + + store.replaceAll({ thr_live: [viewer("bob", true)] }); + + expect(store.getThreadViewers("thr_stale")).toEqual([]); + expect(store.getSummaryHandles("thr_stale")).toEqual([]); + expect(store.getThreadViewers("thr_live").map((v) => v.handle)).toEqual([ + "bob", + ]); + // Summary handles derive from the snapshot's viewer rosters. + expect(store.getSummaryHandles("thr_live")).toEqual(["bob"]); + }); + + it("returns a stable reference for an unchanged roster", () => { + const store = new PresenceStore(); + store.setThreadViewers("thr_1", [viewer("alice")]); + const first = store.getThreadViewers("thr_1"); + store.setThreadViewers("thr_2", [viewer("bob")]); + expect(store.getThreadViewers("thr_1")).toBe(first); + }); +}); diff --git a/apps/app/src/lib/presence-store.ts b/apps/app/src/lib/presence-store.ts new file mode 100644 index 0000000000..8751a6c967 --- /dev/null +++ b/apps/app/src/lib/presence-store.ts @@ -0,0 +1,161 @@ +import { useSyncExternalStore } from "react"; +import type { PresenceViewer } from "@bb/server-contract"; +import { apiClient } from "./api-server"; +import { request } from "./api"; +import type { PresenceSnapshotResponse } from "@bb/server-contract"; +import { wsManager, type WebSocketManager } from "./ws"; + +/** + * Client-side presence read model, fed by the realtime socket: + * - `thread-presence` replaces one thread's full viewer roster (empty removes) + * - `presence-summary` is a partial patch of threadId -> viewer handles for + * the sidebar (an empty handle array removes the entry) + * - the GET /api/v1/presence snapshot re-seeds everything on (re)connect, + * flushing rosters that went stale while the socket was down. + * + * All state is ephemeral — nothing persists across reloads. + */ + +const EMPTY_VIEWERS: readonly PresenceViewer[] = []; +const EMPTY_HANDLES: readonly string[] = []; + +export class PresenceStore { + private viewersByThreadId = new Map(); + private summaryHandlesByThreadId = new Map(); + private listeners = new Set<() => void>(); + + attach(manager: WebSocketManager): () => void { + const unsubscribePresence = manager.onThreadPresence((message) => { + this.setThreadViewers(message.threadId, message.viewers); + }); + const unsubscribeSummary = manager.onPresenceSummary((message) => { + this.patchSummary(message.threads); + }); + const unsubscribeConnected = manager.onConnected(() => { + void this.seedFromSnapshot(); + }); + return () => { + unsubscribePresence(); + unsubscribeSummary(); + unsubscribeConnected(); + }; + } + + private async seedFromSnapshot(): Promise { + let snapshot: PresenceSnapshotResponse; + try { + snapshot = await request( + apiClient.presence.$get(), + ); + } catch { + // Presence is cosmetic; a failed seed just waits for live broadcasts. + return; + } + this.replaceAll(snapshot.threads); + } + + /** Full-state replace from the HTTP snapshot (complete current rosters). */ + replaceAll( + threads: Record, + ): void { + this.viewersByThreadId = new Map(); + this.summaryHandlesByThreadId = new Map(); + for (const [threadId, viewers] of Object.entries(threads)) { + if (viewers.length === 0) { + continue; + } + this.viewersByThreadId.set(threadId, viewers); + this.summaryHandlesByThreadId.set( + threadId, + viewers.map((viewer) => viewer.handle), + ); + } + this.notify(); + } + + setThreadViewers( + threadId: string, + viewers: readonly PresenceViewer[], + ): void { + if (viewers.length === 0) { + this.viewersByThreadId.delete(threadId); + } else { + this.viewersByThreadId.set(threadId, viewers); + } + this.notify(); + } + + patchSummary(threads: Record): void { + for (const [threadId, handles] of Object.entries(threads)) { + if (handles.length === 0) { + this.summaryHandlesByThreadId.delete(threadId); + } else { + this.summaryHandlesByThreadId.set(threadId, handles); + } + } + this.notify(); + } + + getThreadViewers(threadId: string): readonly PresenceViewer[] { + return this.viewersByThreadId.get(threadId) ?? EMPTY_VIEWERS; + } + + getSummaryHandles(threadId: string): readonly string[] { + return this.summaryHandlesByThreadId.get(threadId) ?? EMPTY_HANDLES; + } + + subscribe = (listener: () => void): (() => void) => { + this.listeners.add(listener); + return () => { + this.listeners.delete(listener); + }; + }; + + private notify(): void { + for (const listener of this.listeners) { + listener(); + } + } +} + +// Singleton mirroring the wsManager pattern — preserved across Vite HMR so +// presence state and its socket listeners survive module re-evaluation. +function createOrReuse(): PresenceStore { + if (import.meta.hot?.data) { + const existing = import.meta.hot.data.presenceStore as + | PresenceStore + | undefined; + if (existing) return existing; + const instance = new PresenceStore(); + instance.attach(wsManager); + import.meta.hot.data.presenceStore = instance; + return instance; + } + const instance = new PresenceStore(); + instance.attach(wsManager); + return instance; +} + +export const presenceStore = createOrReuse(); + +/** Live viewer roster for one thread (stable reference until it changes). */ +export function useThreadPresenceViewers( + threadId: string, +): readonly PresenceViewer[] { + return useSyncExternalStore( + presenceStore.subscribe, + () => presenceStore.getThreadViewers(threadId), + () => EMPTY_VIEWERS, + ); +} + +/** Sidebar-summary viewer handles for one thread. */ +export function useThreadPresenceSummaryHandles( + threadId: string, +): readonly string[] { + return useSyncExternalStore( + presenceStore.subscribe, + () => presenceStore.getSummaryHandles(threadId), + () => EMPTY_HANDLES, + ); +} diff --git a/apps/app/src/lib/ws.presence.test.ts b/apps/app/src/lib/ws.presence.test.ts new file mode 100644 index 0000000000..f38a7cc2b5 --- /dev/null +++ b/apps/app/src/lib/ws.presence.test.ts @@ -0,0 +1,70 @@ +import { describe, expect, it, vi } from "vitest"; +import { WebSocketManager } from "./ws"; + +describe("WebSocketManager presence routing", () => { + it("dispatches thread-presence rosters with lenient per-viewer defaults", () => { + const manager = new WebSocketManager(); + const received = vi.fn(); + manager.onThreadPresence(received); + + manager.handleIncomingMessage( + JSON.stringify({ + type: "thread-presence", + threadId: "thr_1", + viewers: [ + { + handle: "alice", + displayName: "Alice", + imageUrl: null, + typing: true, + // Additive field from a newer server must not drop the roster. + futureField: "ignored", + }, + ], + }), + ); + + expect(received).toHaveBeenCalledTimes(1); + expect(received.mock.calls[0]?.[0]).toEqual({ + type: "thread-presence", + threadId: "thr_1", + viewers: [ + { handle: "alice", displayName: "Alice", imageUrl: null, typing: true }, + ], + }); + }); + + it("dispatches presence-summary patches including empty-array removals", () => { + const manager = new WebSocketManager(); + const received = vi.fn(); + manager.onPresenceSummary(received); + + manager.handleIncomingMessage( + JSON.stringify({ + type: "presence-summary", + threads: { thr_1: ["alice"], thr_2: [] }, + }), + ); + + expect(received).toHaveBeenCalledWith({ + type: "presence-summary", + threads: { thr_1: ["alice"], thr_2: [] }, + }); + }); + + it("does not misroute presence messages to changed-message subscribers", () => { + const manager = new WebSocketManager(); + const changed = vi.fn(); + manager.onChanged(changed); + + manager.handleIncomingMessage( + JSON.stringify({ + type: "thread-presence", + threadId: "thr_1", + viewers: [], + }), + ); + + expect(changed).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/app/src/lib/ws.ts b/apps/app/src/lib/ws.ts index d996d3f15d..a2a5504194 100644 --- a/apps/app/src/lib/ws.ts +++ b/apps/app/src/lib/ws.ts @@ -2,25 +2,32 @@ import ReconnectingWebSocket from "partysocket/ws"; import { changedMessageLenientSchema, pluginSignalLenientSchema, + presenceSummaryMessageLenientSchema, realtimeSubscriptionTargetKey, threadOpenSignalLenientSchema, threadPaneActionSignalLenientSchema, + threadPresenceMessageLenientSchema, } from "@bb/server-contract"; import type { ClientMessage, ChangedMessage, PluginSignal, + PresenceSummaryMessage, RealtimeSubscriptionTarget, ThreadOpenFile, ThreadOpenSignal, ThreadPaneActionSignal, + ThreadPresenceMessage, } from "@bb/server-contract"; import { buildDevWebSocketUrl } from "./dev-websocket-url"; +import { getClaimedIdentityHeaderValue } from "./claimed-identity-store"; type ChangeCallback = (message: ChangedMessage) => void; type ThreadOpenCallback = (signal: ThreadOpenSignal) => void; type ThreadPaneActionCallback = (signal: ThreadPaneActionSignal) => void; type PluginSignalCallback = (signal: PluginSignal) => void; +type ThreadPresenceCallback = (message: ThreadPresenceMessage) => void; +type PresenceSummaryCallback = (message: PresenceSummaryMessage) => void; type ConnectedCallback = (event: { reconnected: boolean }) => void; type ConnectionStateCallback = () => void; export type WebSocketConnectionState = @@ -40,6 +47,8 @@ export class WebSocketManager { private threadOpenCallbacks = new Set(); private threadPaneActionCallbacks = new Set(); private pluginSignalCallbacks = new Set(); + private threadPresenceCallbacks = new Set(); + private presenceSummaryCallbacks = new Set(); // Ephemeral "open this file in the secondary panel" intents, keyed by thread. // Held in memory only (cleared on reload) so a thread that is not currently // viewed opens the file when it is next viewed. Last write wins per thread. @@ -55,11 +64,19 @@ export class WebSocketManager { // In dev mode, connect directly to the server to bypass Vite's WS proxy // which does not handle reconnection after backend restarts. // In production, use the same origin (server serves the app). - const url = - buildDevWebSocketUrl({ path: "/ws" }) ?? - `${window.location.protocol === "https:" ? "wss:" : "ws:"}//${window.location.host}/ws`; + // A URL provider (not a string) so every reconnect re-reads the claimed + // identity — an identity claimed after connect rides the next upgrade. + const buildUrl = () => { + const url = + buildDevWebSocketUrl({ path: "/ws" }) ?? + `${window.location.protocol === "https:" ? "wss:" : "ws:"}//${window.location.host}/ws`; + const identity = getClaimedIdentityHeaderValue(); + return identity === null + ? url + : `${url}?identity=${encodeURIComponent(identity)}`; + }; - this.socket = new ReconnectingWebSocket(url, undefined, { + this.socket = new ReconnectingWebSocket(buildUrl, undefined, { minReconnectionDelay: 1000, maxReconnectionDelay: 30000, reconnectionDelayGrowFactor: 1.5, @@ -141,6 +158,25 @@ export class WebSocketManager { return; } + // Ephemeral presence broadcasts: per-thread viewer rosters and the compact + // sidebar summary. Lenient parse — additive per-viewer fields from a newer + // server degrade to defaults instead of dropping the roster. + const threadPresence = threadPresenceMessageLenientSchema.safeParse(parsed); + if (threadPresence.success) { + for (const cb of this.threadPresenceCallbacks) { + cb(threadPresence.data); + } + return; + } + + const presenceSummary = presenceSummaryMessageLenientSchema.safeParse(parsed); + if (presenceSummary.success) { + for (const cb of this.presenceSummaryCallbacks) { + cb(presenceSummary.data); + } + return; + } + // Lenient parse: tolerate a newer server (unknown fields stripped, // unknown change kinds filtered) instead of dropping whole messages // on additive contract changes. @@ -221,6 +257,29 @@ export class WebSocketManager { }; } + onThreadPresence(callback: ThreadPresenceCallback): () => void { + this.threadPresenceCallbacks.add(callback); + return () => { + this.threadPresenceCallbacks.delete(callback); + }; + } + + onPresenceSummary(callback: PresenceSummaryCallback): () => void { + this.presenceSummaryCallbacks.add(callback); + return () => { + this.presenceSummaryCallbacks.delete(callback); + }; + } + + /** + * Ephemeral composer-typing signal; the server holds it under a short TTL, + * so callers re-send `typing: true` while typing continues. Dropped silently + * when the socket is down — presence is cosmetic. + */ + sendTyping(threadId: string, typing: boolean): void { + this.sendMessage({ type: "typing", threadId, typing }); + } + /** * Return and clear the buffered "open file" intent for a thread, if any. The * secondary panel calls this when the thread becomes visible so the file diff --git a/apps/app/src/views/SettingsView.tsx b/apps/app/src/views/SettingsView.tsx index b196d793bb..688c74a702 100644 --- a/apps/app/src/views/SettingsView.tsx +++ b/apps/app/src/views/SettingsView.tsx @@ -49,6 +49,7 @@ import { UpdatesSettingsSection } from "@/components/settings/UpdatesSettingsSec import { KeyboardSettingsSection } from "@/components/settings/KeyboardSettingsSection"; import { MachinesSettingsSection } from "@/components/settings/MachinesSettingsSection"; import { ArchivedThreadsSettingsSection } from "@/components/settings/ArchivedThreadsSettingsSection"; +import { IdentitySettingsSection } from "@/components/settings/IdentitySettingsSection"; import { useUpdateGeneralSettings, useUpdateAppearance, @@ -1001,6 +1002,8 @@ export function SettingsView() { } /> ); + } else if (activeSection === "identity") { + content = ; } else if (activeSection === "appearance") { content = ( void; /** Plugin-contributed thread action buttons (design §4.9); optional. */ pluginActions?: ReactNode; + /** Avatar row of the other collaborators currently viewing this thread. */ + presenceIndicator?: ReactNode; threadHeaderGitActions: ThreadHeaderGitAction[]; threadTitle: string; workspaceOpenButton?: ReactNode; @@ -60,6 +62,7 @@ export function ThreadDetailHeader({ onOpenThreadGitAction, onToggleSecondaryPanel, pluginActions, + presenceIndicator, threadHeaderGitActions, threadTitle, workspaceOpenButton, @@ -153,6 +156,7 @@ export function ThreadDetailHeader({ const actions = ( <> + {presenceIndicator} {pluginActions} {workspaceOpenButton} {primaryAction && secondaryActions.length > 0 ? ( diff --git a/apps/app/src/views/thread-detail/ThreadDetailPromptArea.tsx b/apps/app/src/views/thread-detail/ThreadDetailPromptArea.tsx index 6ce3cc55ae..079425fc70 100644 --- a/apps/app/src/views/thread-detail/ThreadDetailPromptArea.tsx +++ b/apps/app/src/views/thread-detail/ThreadDetailPromptArea.tsx @@ -91,6 +91,8 @@ import { type FollowUpSubmitMode, } from "@/components/promptbox/FollowUpPromptBox"; import { withAutomationPromptAction } from "@/components/promptbox/PromptBoxActionsMenu"; +import { ThreadTypingIndicator } from "@/components/thread/presence/ThreadPresenceIndicators"; +import { useTypingEmitter } from "@/hooks/useTypingEmitter"; import { queuedInputToDraft } from "./threadQueuedMessages"; import type { SendMessageMutationLike } from "./threadDetailMutationTypes"; import { @@ -618,6 +620,11 @@ export function ThreadDetailPromptArea({ }, [inlineEditingQueuedMessage, removeStoredPromptAttachment], ); + useTypingEmitter({ + threadId: thread.id, + draftText: activeComposerDraft.text, + enabled: !shouldHideComposer, + }); const hasPromptDraftInput = currentPromptDraftInput.length > 0; const isPromptEmpty = useCallback( () => !hasPromptDraftInput, @@ -1344,6 +1351,7 @@ export function ThreadDetailPromptArea({ const promptStack = useMemo( () => ( <> + } + presenceIndicator={} threadHeaderGitActions={gitActions.threadHeaderGitActions} threadTitle={threadTitle} workspaceOpenButton={workspaceOpenButton} diff --git a/apps/cli/src/__tests__/command-output/members.test.ts b/apps/cli/src/__tests__/command-output/members.test.ts new file mode 100644 index 0000000000..da905125a1 --- /dev/null +++ b/apps/cli/src/__tests__/command-output/members.test.ts @@ -0,0 +1,96 @@ +import { describe, expect, it, vi } from "vitest"; +import { + collectLogLines, + collectLogPayloads, + getHelpOutput, + runCommand, + setupCommandOutputTestEnvironment, + stubServerApi, + type CommandRegistrar, +} from "../helpers/command-output-harness.js"; +import { registerMembersCommands } from "../../commands/members.js"; + +const member = { + userId: "member-1", + handle: "collaborator", + displayName: "Collaborator", + imageUrl: null, + addedByUserId: "owner-1", + createdAt: 123, +}; + +describe("bb members commands", () => { + setupCommandOutputTestEnvironment(); + + const register: CommandRegistrar = (program) => + registerMembersCommands(program, () => "http://server"); + + it("lists members in human and JSON output", async () => { + stubServerApi({ + "v1.members.$get": vi.fn(async () => ({ members: [member] })), + }); + + await runCommand(["members", "list"], register); + expect(collectLogLines(vi.mocked(console.log)).join("\n")).toContain( + "collaborator", + ); + + vi.mocked(console.log).mockClear(); + await runCommand(["members", "list", "--json"], register); + expect(collectLogPayloads(vi.mocked(console.log))).toEqual([ + JSON.stringify([member], null, 2), + ]); + }); + + it("adds and removes a member", async () => { + const add = vi.fn(async () => member); + const remove = vi.fn(async () => ({ ok: true })); + stubServerApi({ + "v1.members.$post": add, + "v1.members.$delete": remove, + }); + + await runCommand(["members", "add", "collaborator"], register); + await runCommand(["members", "remove", "collaborator"], register); + + expect(add).toHaveBeenCalledWith({ json: { handle: "collaborator" } }); + expect(remove).toHaveBeenCalledWith({ json: { handle: "collaborator" } }); + expect(collectLogLines(vi.mocked(console.log))).toEqual([ + "Added @collaborator (Collaborator)", + "Removed @collaborator", + ]); + }); + + it.each([ + [404, "connect_not_enrolled", "not enrolled in Connect"], + [404, "unknown_handle", "No Connect account has the handle"], + [409, "already_member", "already a member"], + [403, "member_management_tunnel_forbidden", "owner's local console"], + ])("prints the server's clear %i error", async (status, code, message) => { + stubServerApi({ + "v1.members.$post": vi.fn( + async () => + new Response(JSON.stringify({ code, message }), { + status, + headers: { "content-type": "application/json" }, + }), + ), + }); + + await expect( + runCommand(["members", "add", "collaborator"], register), + ).rejects.toThrow("process.exit:1"); + expect(collectLogLines(vi.mocked(console.error)).join("\n")).toContain( + message, + ); + }); + + it("documents every member command and JSON output", async () => { + const help = await getHelpOutput(["members"], register); + const listHelp = await getHelpOutput(["members", "list"], register); + expect(help).toContain("list"); + expect(help).toContain("add"); + expect(help).toContain("remove"); + expect(listHelp).toContain("--json"); + }); +}); diff --git a/apps/cli/src/__tests__/json-flag-enforcement.test.ts b/apps/cli/src/__tests__/json-flag-enforcement.test.ts index 9996250ba2..98aac677ae 100644 --- a/apps/cli/src/__tests__/json-flag-enforcement.test.ts +++ b/apps/cli/src/__tests__/json-flag-enforcement.test.ts @@ -6,6 +6,7 @@ import { registerProjectCommands } from "../commands/project.js"; import { registerProviderCommands } from "../commands/provider.js"; import { registerManagerCommands } from "../commands/manager.js"; import { registerMachineCommands } from "../commands/machine.js"; +import { registerMembersCommands } from "../commands/members.js"; import { registerThreadCommands } from "../commands/thread/index.js"; // Commands intentionally excluded from --json requirement const EXCLUDED_COMMANDS = new Set(); @@ -37,6 +38,7 @@ describe("CLI --json flag enforcement", () => { registerProviderCommands(program, getUrl); registerManagerCommands(program, getUrl); registerMachineCommands(program, getUrl); + registerMembersCommands(program, getUrl); registerThreadCommands(program, getUrl); const commands = collectLeafCommands(program); diff --git a/apps/cli/src/client.ts b/apps/cli/src/client.ts index 03db38ab7e..f6250bc5f8 100644 --- a/apps/cli/src/client.ts +++ b/apps/cli/src/client.ts @@ -1,7 +1,9 @@ import { createNodeBbSdk, type BbSdk, type BbSdkContext } from "@bb/sdk/node"; +import type { ClaimedIdentity } from "@bb/domain"; export interface CreateCliBbSdkOptions { context?: BbSdkContext; + claimedIdentity?: ClaimedIdentity; } export function cliFetch( @@ -18,6 +20,9 @@ export function createCliBbSdk( return createNodeBbSdk({ baseUrl, context: options.context, + ...(options.claimedIdentity + ? { claimedIdentity: options.claimedIdentity } + : {}), fetch: cliFetch, }); } diff --git a/apps/cli/src/commands/members.ts b/apps/cli/src/commands/members.ts new file mode 100644 index 0000000000..7be36f5ea6 --- /dev/null +++ b/apps/cli/src/commands/members.ts @@ -0,0 +1,82 @@ +import { Command } from "commander"; +import type { Member } from "@bb/server-contract"; +import { action } from "../action.js"; +import { createCliBbSdk } from "../client.js"; +import { renderBorderlessTable } from "../table.js"; +import { outputJson, type JsonOutputOptions } from "./helpers.js"; + +function printMembers(members: Member[]): void { + if (members.length === 0) { + console.log("No members"); + return; + } + const rows = members.map((member) => [ + member.handle, + member.displayName, + member.imageUrl ?? "", + ]); + const widths = [ + Math.max(6, ...rows.map((row) => row[0].length)), + Math.max(4, ...rows.map((row) => row[1].length)), + Math.max(6, ...rows.map((row) => row[2].length)), + ]; + console.log(""); + console.log( + renderBorderlessTable( + { + head: ["Handle", "Name", "Avatar"], + colWidths: widths, + trimTrailingWhitespace: true, + }, + rows, + ), + ); + console.log(""); +} + +export function registerMembersCommands( + program: Command, + getUrl: () => string, +): void { + const members = program + .command("members") + .description("Manage Connect members for this bb"); + + members + .command("list") + .description("List members admitted through Connect") + .option("--json", "Print machine-readable JSON output") + .action( + action(async (options: JsonOutputOptions) => { + const result = await createCliBbSdk(getUrl()).members.list(); + if (outputJson(options, result)) return; + printMembers(result); + }), + ); + + members + .command("add ") + .description("Add a Connect account by handle") + .option("--json", "Print machine-readable JSON output") + .action( + action(async (handle: string, options: JsonOutputOptions) => { + const member = await createCliBbSdk(getUrl()).members.add({ handle }); + if (outputJson(options, member)) return; + console.log(`Added @${member.handle} (${member.displayName})`); + }), + ); + + members + .command("remove ") + .description("Remove a Connect member by handle") + .option("--json", "Print machine-readable JSON output") + .action( + action(async (handle: string, options: JsonOutputOptions) => { + const result = await createCliBbSdk(getUrl()).members.remove({ + handle, + }); + if (outputJson(options, result)) return; + console.log(`Removed @${handle.trim().toLowerCase()}`); + }), + ); +} diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts index f7687d9c00..2ad031ef49 100644 --- a/apps/cli/src/index.ts +++ b/apps/cli/src/index.ts @@ -5,6 +5,7 @@ import { registerEnvironmentCommands } from "./commands/environment.js"; import { registerFileCommands } from "./commands/file.js"; import { registerGuideCommand } from "./commands/guide.js"; import { registerManagerCommands } from "./commands/manager.js"; +import { registerMembersCommands } from "./commands/members.js"; import { registerMachineCommands } from "./commands/machine.js"; import { registerProjectCommands } from "./commands/project.js"; import { registerPluginCommands } from "./commands/plugin.js"; @@ -85,6 +86,7 @@ registerSettingsCommands(program, getUrl); registerProjectCommands(program, getUrl); registerProviderCommands(program, getUrl); registerManagerCommands(program, getUrl); +registerMembersCommands(program, getUrl); registerMachineCommands(program, getUrl); registerTerminalCommands(program, getUrl); registerThreadCommands(program, getUrl); diff --git a/apps/connect/src/members.test.ts b/apps/connect/src/members.test.ts index e89aebe870..7fd6ebfd41 100644 --- a/apps/connect/src/members.test.ts +++ b/apps/connect/src/members.test.ts @@ -31,6 +31,16 @@ let sqlite: Database.Database; let db: ReturnType; let sessionOrdinal = 0; +async function sha256Hex(value: string): Promise { + const digest = await crypto.subtle.digest( + "SHA-256", + new TextEncoder().encode(value), + ); + return [...new Uint8Array(digest)] + .map((byte) => byte.toString(16).padStart(2, "0")) + .join(""); +} + beforeEach(() => { sqlite = new Database(":memory:"); sqlite.pragma("foreign_keys = ON"); @@ -71,14 +81,16 @@ function seedServer( id: string, ownerUserId: string, subdomain = "owner", + credentialHash = "hash", + name = "default", ): void { db.insert(server) .values({ id, userId: ownerUserId, - name: "default", + name, subdomain, - credentialHash: "hash", + credentialHash, createdAt: NOW, }) .run(); @@ -192,6 +204,92 @@ describe("owner member-management API", () => { expect(response.status).toBe(403); }); + it("accepts the same server's tunnel credential across member management", async () => { + const credential = "bbcred_server_one"; + db.update(server) + .set({ credentialHash: await sha256Hex(credential) }) + .where(eq(server.id, "server-1")) + .run(); + + const added = await handleServerMembersWithDb( + new Request("https://getbb.app/api/servers/server-1/members", { + method: "POST", + headers: { authorization: `Bearer ${credential}` }, + body: JSON.stringify({ handle: "invited" }), + }), + SECRET, + db, + route("server-1"), + ); + expect(added.status).toBe(201); + + const listed = await handleServerMembersWithDb( + new Request("https://getbb.app/api/servers/server-1/members", { + headers: { authorization: `Bearer ${credential}` }, + }), + SECRET, + db, + route("server-1"), + ); + expect(listed.status).toBe(200); + await expect(listed.json()).resolves.toEqual([ + expect.objectContaining({ userId: "member-user", handle: "invited" }), + ]); + + const removed = await handleServerMembersWithDb( + new Request( + "https://getbb.app/api/servers/server-1/members/member-user", + { + method: "DELETE", + headers: { authorization: `Bearer ${credential}` }, + }, + ), + SECRET, + db, + route("server-1", "member-user"), + ); + expect(removed.status).toBe(204); + }); + + it("rejects a wrong tunnel credential", async () => { + const response = await handleServerMembersWithDb( + new Request("https://getbb.app/api/servers/server-1/members", { + headers: { authorization: "Bearer wrong" }, + }), + SECRET, + db, + route("server-1"), + ); + + expect(response.status).toBe(403); + }); + + it("cannot use one server credential to manage another server", async () => { + const credential = "bbcred_server_one"; + db.update(server) + .set({ credentialHash: await sha256Hex(credential) }) + .where(eq(server.id, "server-1")) + .run(); + seedServer( + "server-2", + "owner-user", + "owner-two", + "different-hash", + "second", + ); + + const response = await handleServerMembersWithDb( + new Request("https://getbb.app/api/servers/server-2/members", { + headers: { authorization: `Bearer ${credential}` }, + }), + SECRET, + db, + route("server-2"), + ); + + expect(response.status).toBe(403); + }); + it("adds, lists, and removes a member with owner-attributed audit rows", async () => { const addRequest = await sessionRequest( "owner-user", diff --git a/apps/connect/src/members.ts b/apps/connect/src/members.ts index e040c233b6..3013b46019 100644 --- a/apps/connect/src/members.ts +++ b/apps/connect/src/members.ts @@ -292,6 +292,48 @@ async function resolveOwnerSessionUserId( return verifySessionCookie(cookie, secret, db); } +async function sha256Hex(value: string): Promise { + const digest = await crypto.subtle.digest( + "SHA-256", + new TextEncoder().encode(value), + ); + return [...new Uint8Array(digest)] + .map((byte) => byte.toString(16).padStart(2, "0")) + .join(""); +} + +async function resolveServerCredentialOwnerUserId( + request: Request, + serverId: string, + db: ConnectDb, +): Promise { + const authorization = request.headers.get("authorization") ?? ""; + const credential = authorization.startsWith("Bearer ") + ? authorization.slice("Bearer ".length) + : ""; + if (!credential) return null; + + const ownedServer = await db + .select({ + credentialHash: server.credentialHash, + revokedAt: server.revokedAt, + userId: server.userId, + }) + .from(server) + .where(eq(server.id, serverId)) + .get(); + if ( + !ownedServer || + ownedServer.revokedAt !== null || + ownedServer.credentialHash === null + ) { + return null; + } + return (await sha256Hex(credential)) === ownedServer.credentialHash + ? ownedServer.userId + : null; +} + /** Testable owner-session member API using either D1 or in-memory SQLite. */ export async function handleServerMembersWithDb( request: Request, @@ -315,14 +357,23 @@ export async function handleServerMembersWithDb( }); } - const sessionUserId = await resolveOwnerSessionUserId(request, secret, db); - if (!sessionUserId) return jsonError("forbidden", 403); - const ownedServer = await db - .select({ id: server.id }) - .from(server) - .where(and(eq(server.id, route.serverId), eq(server.userId, sessionUserId))) - .get(); - if (!ownedServer) return jsonError("forbidden", 403); + const credentialOwnerUserId = await resolveServerCredentialOwnerUserId( + request, + route.serverId, + db, + ); + const ownerUserId = + credentialOwnerUserId ?? + (await resolveOwnerSessionUserId(request, secret, db)); + if (!ownerUserId) return jsonError("forbidden", 403); + if (credentialOwnerUserId === null) { + const ownedServer = await db + .select({ id: server.id }) + .from(server) + .where(and(eq(server.id, route.serverId), eq(server.userId, ownerUserId))) + .get(); + if (!ownedServer) return jsonError("forbidden", 403); + } if (request.method === "GET") { return Response.json(await listServerMembers(db, route.serverId)); @@ -343,7 +394,7 @@ export async function handleServerMembersWithDb( const result = await addServerMember( db, route.serverId, - sessionUserId, + ownerUserId, body.handle, ); if (!result.ok) { @@ -361,7 +412,7 @@ export async function handleServerMembersWithDb( const removed = await removeServerMember( db, route.serverId, - sessionUserId, + ownerUserId, route.memberUserId!, ); return removed diff --git a/apps/connect/src/servers.test.ts b/apps/connect/src/servers.test.ts index 8112046dcb..54e00dafeb 100644 --- a/apps/connect/src/servers.test.ts +++ b/apps/connect/src/servers.test.ts @@ -157,8 +157,16 @@ describe("listAccountServers", () => { const listed = await listAccountServers(db, "acct-a", now.getTime()); expect(listed).toEqual( expect.arrayContaining([ - { handle: "sawyer", name: "default", live: true }, - { handle: "sawyer-desktop", name: "desktop", live: false }, + expect.objectContaining({ + handle: "sawyer", + name: "default", + live: true, + }), + expect.objectContaining({ + handle: "sawyer-desktop", + name: "desktop", + live: false, + }), ]), ); expect(listed).toHaveLength(2); @@ -196,9 +204,21 @@ describe("listAccountServers", () => { const listed = await listAccountServers(db, "acct-a", now.getTime()); expect(listed).toEqual( expect.arrayContaining([ - { handle: "empty-name", name: "empty-name", live: true }, - { handle: "revoked-box", name: "revoked", live: false }, - { handle: "never-paired", name: "never", live: false }, + expect.objectContaining({ + handle: "empty-name", + name: "empty-name", + live: true, + }), + expect.objectContaining({ + handle: "revoked-box", + name: "revoked", + live: false, + }), + expect.objectContaining({ + handle: "never-paired", + name: "never", + live: false, + }), ]), ); }); diff --git a/apps/connect/src/servers.ts b/apps/connect/src/servers.ts index 3294bac531..b882f95f4a 100644 --- a/apps/connect/src/servers.ts +++ b/apps/connect/src/servers.ts @@ -185,6 +185,8 @@ export async function resolveAccountUserId( } export interface AccountServerListing { + /** Stable server id used by owner-only server-scoped APIs. */ + id: string; /** Routing label (`server.subdomain`) — `.getbb.app`. */ handle: string; /** Human-readable row name; falls back to handle when empty. */ @@ -209,6 +211,7 @@ export async function listAccountServers( ): Promise { const rows = await db .select({ + id: server.id, subdomain: server.subdomain, name: server.name, lastSeenAt: server.lastSeenAt, @@ -229,7 +232,7 @@ export async function listAccountServers( connected && lastSeenMs != null && now - lastSeenMs < SERVER_OFFLINE_AFTER_MS; - return { handle, name, live }; + return { id: row.id, handle, name, live }; }); } diff --git a/apps/server/src/routes/members.ts b/apps/server/src/routes/members.ts new file mode 100644 index 0000000000..9f90384a29 --- /dev/null +++ b/apps/server/src/routes/members.ts @@ -0,0 +1,311 @@ +import { getPluginKvValue } from "@bb/db"; +import { normalizeHandle } from "@bb/domain"; +import { + memberListResponseSchema, + memberSchema, + publicApiRoutes, + typedRoutes, + type Member, + type PublicApiSchema, +} from "@bb/server-contract"; +import type { Hono } from "hono"; +import { z } from "zod"; +import { ApiError } from "../errors.js"; +import type { AppDeps } from "../types.js"; + +const CONNECT_PLUGIN_ID = "connect"; +const CONNECT_CREDENTIAL_KEY = "credential"; +const TUNNEL_ORIGIN_HEADER = "x-bb-via-tunnel"; + +const connectCredentialSchema = z + .object({ + serverUrl: z.string().url(), + handle: z.string().min(1), + credential: z.string().min(1), + }) + .strict(); + +const accountServersResponseSchema = z + .object({ + servers: z.array( + z.object({ + id: z.string().min(1), + handle: z.string().min(1), + }), + ), + }) + .strict(); + +const workerMemberSchema = z + .object({ + userId: z.string().min(1), + handle: z.string().min(1), + name: z.string().min(1), + image: z.string().nullable(), + addedByUserId: z.string().min(1), + createdAt: z.number().int().nonnegative(), + }) + .strict(); + +interface MemberProxyTarget { + credential: string; + memberApiUrl: string; +} + +function assertOwnerConsoleRequest(request: Request): void { + if (request.headers.has(TUNNEL_ORIGIN_HEADER)) { + throw new ApiError( + 403, + "member_management_tunnel_forbidden", + "Member management is available only from the owner's local console", + ); + } +} + +function readConnectCredential(deps: AppDeps) { + const stored = getPluginKvValue( + deps.db, + CONNECT_PLUGIN_ID, + CONNECT_CREDENTIAL_KEY, + ); + if (stored === undefined) { + throw new ApiError( + 404, + "connect_not_enrolled", + "This bb is not enrolled in Connect; pair it before managing members", + ); + } + let raw: unknown; + try { + raw = JSON.parse(stored); + } catch { + throw new ApiError( + 404, + "connect_not_enrolled", + "This bb has no valid Connect enrollment", + ); + } + const parsed = connectCredentialSchema.safeParse(raw); + if (!parsed.success) { + throw new ApiError( + 404, + "connect_not_enrolled", + "This bb has no valid Connect enrollment", + ); + } + return parsed.data; +} + +async function jsonFromWorker(response: Response): Promise { + try { + return await response.json(); + } catch { + throw new ApiError( + 502, + "connect_invalid_response", + "Connect returned an invalid response", + ); + } +} + +function workerErrorCode(raw: unknown): string | null { + if ( + typeof raw === "object" && + raw !== null && + "error" in raw && + typeof raw.error === "string" + ) { + return raw.error; + } + return null; +} + +async function throwWorkerError( + response: Response, + handle?: string, +): Promise { + const raw = await jsonFromWorker(response); + const code = workerErrorCode(raw); + if (response.status === 403) { + throw new ApiError( + 403, + "member_management_forbidden", + "Connect rejected member management for this server", + ); + } + if (response.status === 404 && code === "unknown_handle") { + throw new ApiError( + 404, + "unknown_handle", + `No Connect account has the handle '${handle ?? ""}'`, + ); + } + if (response.status === 404) { + throw new ApiError(404, "member_not_found", "Member not found"); + } + if (response.status === 409 && code === "already_member") { + throw new ApiError( + 409, + "already_member", + `The handle '${handle ?? ""}' is already a member`, + ); + } + throw new ApiError( + response.status === 400 + ? 400 + : response.status === 401 + ? 401 + : response.status === 405 + ? 405 + : 502, + code ?? "connect_request_failed", + `Connect member request failed (${response.status})`, + ); +} + +async function fetchWorker( + input: string, + init: RequestInit, +): Promise { + try { + return await fetch(input, init); + } catch (error) { + throw new ApiError( + 502, + "connect_unreachable", + `Connect is unreachable: ${error instanceof Error ? error.message : String(error)}`, + ); + } +} + +async function resolveMemberProxyTarget( + deps: AppDeps, +): Promise { + const enrollment = readConnectCredential(deps); + const serverUrl = enrollment.serverUrl.replace(/\/+$/u, ""); + const response = await fetchWorker(`${serverUrl}/api/connect/servers`, { + headers: { "x-bb-connect-machine": enrollment.credential }, + }); + if (!response.ok) { + if (response.status === 401 || response.status === 403) { + throw new ApiError( + 403, + "connect_enrollment_rejected", + "Connect rejected this bb's enrollment credential", + ); + } + await throwWorkerError(response); + } + const parsed = accountServersResponseSchema.safeParse( + await jsonFromWorker(response), + ); + if (!parsed.success) { + throw new ApiError( + 502, + "connect_invalid_response", + "Connect returned an invalid server identity response", + ); + } + const ownServer = parsed.data.servers.find( + (server) => server.handle === enrollment.handle, + ); + if (!ownServer) { + throw new ApiError( + 404, + "connect_not_enrolled", + "This bb's Connect enrollment no longer identifies a server", + ); + } + return { + credential: enrollment.credential, + memberApiUrl: `${serverUrl}/api/servers/${encodeURIComponent(ownServer.id)}/members`, + }; +} + +function memberFromWorker(raw: unknown): Member { + const member = workerMemberSchema.safeParse(raw); + if (!member.success) { + throw new ApiError( + 502, + "connect_invalid_response", + "Connect returned an invalid member", + ); + } + return memberSchema.parse({ + userId: member.data.userId, + handle: member.data.handle, + displayName: member.data.name, + imageUrl: member.data.image, + addedByUserId: member.data.addedByUserId, + createdAt: member.data.createdAt, + }); +} + +async function listMembers(target: MemberProxyTarget): Promise { + const response = await fetchWorker(target.memberApiUrl, { + headers: { authorization: `Bearer ${target.credential}` }, + }); + if (!response.ok) await throwWorkerError(response); + const raw = await jsonFromWorker(response); + if (!Array.isArray(raw)) { + throw new ApiError( + 502, + "connect_invalid_response", + "Connect returned an invalid member list", + ); + } + return raw.map(memberFromWorker); +} + +export function registerMemberRoutes(app: Hono, deps: AppDeps): void { + const { del, get, post } = typedRoutes(app, { + onValidationError: (message) => + new ApiError(400, "invalid_request", message), + }); + + get(publicApiRoutes.members.list, async (context) => { + assertOwnerConsoleRequest(context.req.raw); + const members = await listMembers(await resolveMemberProxyTarget(deps)); + return context.json(memberListResponseSchema.parse({ members })); + }); + + post(publicApiRoutes.members.add, async (context, input) => { + assertOwnerConsoleRequest(context.req.raw); + const target = await resolveMemberProxyTarget(deps); + const response = await fetchWorker(target.memberApiUrl, { + method: "POST", + headers: { + authorization: `Bearer ${target.credential}`, + "content-type": "application/json", + }, + body: JSON.stringify({ handle: normalizeHandle(input.handle) }), + }); + if (!response.ok) await throwWorkerError(response, input.handle); + return context.json(memberFromWorker(await jsonFromWorker(response)), 201); + }); + + del(publicApiRoutes.members.remove, async (context, input) => { + assertOwnerConsoleRequest(context.req.raw); + const target = await resolveMemberProxyTarget(deps); + const normalizedHandle = normalizeHandle(input.handle); + const member = (await listMembers(target)).find( + (candidate) => normalizeHandle(candidate.handle) === normalizedHandle, + ); + if (!member) { + throw new ApiError( + 404, + "unknown_handle", + `The handle '${input.handle}' is not a member`, + ); + } + const response = await fetchWorker( + `${target.memberApiUrl}/${encodeURIComponent(member.userId)}`, + { + method: "DELETE", + headers: { authorization: `Bearer ${target.credential}` }, + }, + ); + if (!response.ok) await throwWorkerError(response, input.handle); + return context.json({ ok: true }); + }); +} diff --git a/apps/server/src/server.ts b/apps/server/src/server.ts index dff56768a2..562af06c74 100644 --- a/apps/server/src/server.ts +++ b/apps/server/src/server.ts @@ -17,6 +17,7 @@ import { registerEnvironmentRoutes } from "./routes/environments.js"; import { registerFileRoutes } from "./routes/files.js"; import { registerHostRoutes } from "./routes/hosts.js"; import { registerPresenceRoutes } from "./routes/presence.js"; +import { registerMemberRoutes } from "./routes/members.js"; import { registerProjectRoutes } from "./routes/projects.js"; import { registerThreadSectionRoutes } from "./routes/thread-sections.js"; import { registerSystemRoutes } from "./routes/system.js"; @@ -465,6 +466,7 @@ export function createApp( registerEnvironmentRoutes(publicApi, deps); registerThreadRoutes(publicApi, deps); registerPresenceRoutes(publicApi, deps); + registerMemberRoutes(publicApi, deps); registerSystemRoutes(publicApi, deps, pluginService); registerPluginCatalogRoutes(publicApi, pluginCatalogService); registerPluginRoutes(publicApi, deps, pluginService); diff --git a/apps/server/src/services/skills/builtin-skills/bb-cli/SKILL.md b/apps/server/src/services/skills/builtin-skills/bb-cli/SKILL.md index ebae74c25e..559ef11682 100644 --- a/apps/server/src/services/skills/builtin-skills/bb-cli/SKILL.md +++ b/apps/server/src/services/skills/builtin-skills/bb-cli/SKILL.md @@ -35,6 +35,21 @@ message agents, or inspect projects, providers, and environments. server does not read the file. - Use `bb-app client ssh-target list --json` to inspect mappings. +## Multiplayer Members + +- `bb members list|add |remove ` manages which Connect + accounts may access this bb through the gate (all subcommands take + `--json`). Members get full app access; their messages and actions are + attributed to their claimed identity, and presence shows who is viewing or + typing in each thread. +- Member management is owner-console-only: it is rejected for sessions + arriving through the Connect tunnel, and requires the server to be enrolled + in Connect. +- Identity is claimed, not verified: clients self-assert a handle via the + `x-bb-claimed-identity` header (SDK clients can set it via the + `claimedIdentity` option). Requests without one attribute to the machine's + local operator. + ## App Settings - Settings → General holds server-backed app-wide preferences, such as the diff --git a/apps/server/test/public/public-members.test.ts b/apps/server/test/public/public-members.test.ts new file mode 100644 index 0000000000..2882907a1f --- /dev/null +++ b/apps/server/test/public/public-members.test.ts @@ -0,0 +1,95 @@ +import { setPluginKvValue } from "@bb/db"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { readJson } from "../helpers/json.js"; +import { withTestHarness } from "../helpers/test-app.js"; + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +describe("/api/v1/members", () => { + it("rejects tunnel-originated member management", async () => { + await withTestHarness(async (harness) => { + const response = await harness.app.request("/api/v1/members", { + headers: { "x-bb-via-tunnel": "1" }, + }); + + expect(response.status).toBe(403); + await expect(readJson(response)).resolves.toMatchObject({ + code: "member_management_tunnel_forbidden", + }); + }); + }); + + it("returns a clear not-enrolled error without a Connect credential", async () => { + await withTestHarness(async (harness) => { + const response = await harness.app.request("/api/v1/members"); + + expect(response.status).toBe(404); + await expect(readJson(response)).resolves.toMatchObject({ + code: "connect_not_enrolled", + }); + }); + }); + + it("resolves the enrolled server and proxies its member list", async () => { + await withTestHarness(async (harness) => { + setPluginKvValue( + harness.db, + "connect", + "credential", + JSON.stringify({ + serverUrl: "https://owner.getbb.app", + handle: "owner", + credential: "bbcred_owner", + }), + ); + const fetchMock = vi + .fn() + .mockResolvedValueOnce( + Response.json({ + servers: [{ id: "server-1", handle: "owner" }], + }), + ) + .mockResolvedValueOnce( + Response.json([ + { + userId: "member-1", + handle: "collaborator", + name: "Collaborator", + image: null, + addedByUserId: "owner-user", + createdAt: 123, + }, + ]), + ); + vi.stubGlobal("fetch", fetchMock); + + const response = await harness.app.request("/api/v1/members"); + + expect(response.status).toBe(200); + await expect(readJson(response)).resolves.toEqual({ + members: [ + { + userId: "member-1", + handle: "collaborator", + displayName: "Collaborator", + imageUrl: null, + addedByUserId: "owner-user", + createdAt: 123, + }, + ], + }); + expect(fetchMock).toHaveBeenNthCalledWith( + 1, + "https://owner.getbb.app/api/connect/servers", + { headers: { "x-bb-connect-machine": "bbcred_owner" } }, + ); + expect(fetchMock).toHaveBeenNthCalledWith( + 2, + "https://owner.getbb.app/api/servers/server-1/members", + { headers: { authorization: "Bearer bbcred_owner" } }, + ); + }); + }); +}); diff --git a/docs/agent-api-cli-parity.md b/docs/agent-api-cli-parity.md index af68d513ee..f6abca7448 100644 --- a/docs/agent-api-cli-parity.md +++ b/docs/agent-api-cli-parity.md @@ -215,6 +215,45 @@ The SDK area is named `hosts`; the end-user CLI terminology is `machine`. Provider CLI keys are `claudeCode`, `codex`, and `cursor`. +## Multiplayer identity, presence, and members + +Clients may claim an attribution identity when they are created. Identity is +self-asserted metadata, not authorization; Connect admission remains the +security boundary. + +```ts +const bb = createNodeBbSdk({ + claimedIdentity: { + handle: "collaborator", + displayName: "Collaborator", + imageUrl: null, + clientId: "automation-1", + }, +}); + +const presence = await bb.presence.get(); +``` + +The SDK sends the encoded `x-bb-claimed-identity` value on HTTP requests and +the equivalent `identity` query parameter on its realtime WebSocket. Without a +claimed identity, the local server attributes activity to its local-operator +default. `presence.get()` returns the complete current per-thread viewer and +typing snapshot; realtime presence messages remain the low-latency update +path. + +Connect member management has matching SDK and CLI surfaces: + +| SDK | CLI | +| ------------------------------- | ---------------------------- | +| `bb.members.list()` | `bb members list` | +| `bb.members.add({ handle })` | `bb members add ` | +| `bb.members.remove({ handle })` | `bb members remove ` | + +All three CLI commands support `--json`. They are owner-console-only: a request +that arrived through the Connect tunnel is rejected even if a remote member +can otherwise use the bb server. The connect worker owns the authoritative +member list, so these commands require this bb to be enrolled in Connect. + ## Settings and system information The SDK methods live under `bb.system`: diff --git a/docs/plugin-api-and-sdk-reference.md b/docs/plugin-api-and-sdk-reference.md index 3a22019bc5..cd846f679b 100644 --- a/docs/plugin-api-and-sdk-reference.md +++ b/docs/plugin-api-and-sdk-reference.md @@ -239,17 +239,17 @@ Commands should still page or otherwise bound naturally growing collections; the shared ceiling is the final safety boundary, not a substitute for efficient queries. The repository-owned command audit is: -| Plugin command | Potential growth | Bounded contract / remediation | -| --- | --- | --- | -| `bb automation` | automation lists, run history, stored script output | `runs` defaults to 50 and accepts `--limit`; stored script output is capped; all remaining responses fail atomically at the shared ceiling. | -| `bb connect` | servers and shared ports | Account and host share inventories are externally bounded; the shared ceiling remains the final guard. | -| `bb instructions` | one configured instruction document | Single-record output; an oversized value fails atomically at the shared ceiling. | -| `bb workflows` | run lists, status payloads, call history | `list` is capped at 50, `history` is cursor-paged at 1–100 records, and status/list fields and inline results have byte caps. | -| `bb secret` | request metadata | Secret values are never returned; output is fixed-size request/reconciliation metadata. | -| `bb github` | repositories and cached issues/PRs | Issue/PR output can be narrowed to one `owner/repo`; any still-oversized cache response fails atomically with guidance to narrow the query. | -| `bb docs` | vault trees, note content, status/diffs | Discovery can be scoped by vault/path and large content should use `pull` to a workspace; oversized inline responses fail atomically with file/streaming guidance. | -| `bb memory` | catalog/search results, record history, one large record | Catalog/search and history use `--limit` with a 1–100 range; a single oversized record fails atomically. | -| `bb tasks` | task collections and rich task detail | `list` uses SQL keyset pagination (`--limit` 1–500, opaque `--cursor`); detail/scoped auxiliary lists remain protected by the shared ceiling. | +| Plugin command | Potential growth | Bounded contract / remediation | +| ----------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `bb automation` | automation lists, run history, stored script output | `runs` defaults to 50 and accepts `--limit`; stored script output is capped; all remaining responses fail atomically at the shared ceiling. | +| `bb connect` | servers and shared ports | Account and host share inventories are externally bounded; the shared ceiling remains the final guard. | +| `bb instructions` | one configured instruction document | Single-record output; an oversized value fails atomically at the shared ceiling. | +| `bb workflows` | run lists, status payloads, call history | `list` is capped at 50, `history` is cursor-paged at 1–100 records, and status/list fields and inline results have byte caps. | +| `bb secret` | request metadata | Secret values are never returned; output is fixed-size request/reconciliation metadata. | +| `bb github` | repositories and cached issues/PRs | Issue/PR output can be narrowed to one `owner/repo`; any still-oversized cache response fails atomically with guidance to narrow the query. | +| `bb docs` | vault trees, note content, status/diffs | Discovery can be scoped by vault/path and large content should use `pull` to a workspace; oversized inline responses fail atomically with file/streaming guidance. | +| `bb memory` | catalog/search results, record history, one large record | Catalog/search and history use `--limit` with a 1–100 range; a single oversized record fails atomically. | +| `bb tasks` | task collections and rich task detail | `list` uses SQL keyset pagination (`--limit` 1–500, opaque `--cursor`); detail/scoped auxiliary lists remain protected by the shared ceiling. | ### `bb.ui.requestInput` @@ -780,6 +780,8 @@ All names below are exported portable aliases (except the generic `TOutput`, con - `files`: `read → FileReadResult`, `write → FileWriteResult`, `list → FileListResult`, `listPaths → PathListResult`, `mkdir → FileMkdirResult`, `move → FileMoveResult`, `remove → FileRemoveResult`, `createPreview → FilePreviewResult`. - `guide`: `render → GuideRenderResult` synchronously. - `hosts`: `createJoinCode → HostCreateJoinCodeResult`, `delete → HostDeleteResult`, `directory → HostDirectoryResult`, `get → HostGetResult`, `cloneDefaultPath → HostCloneDefaultPathResult`, `installProviderCli → HostProviderCliInstallResult`, `list → HostListResult`, `pathsExist → HostPathsExistResult`, `pickFolder → HostPickFolderResult`, `providerCliStatus → HostProviderCliStatusResult`, `update → HostUpdateResult`. +- `members`: `add → MemberAddResult`, `list → MemberListResult`, `remove → MemberRemoveResult`; the connect worker owns the authoritative member list and mutations are owner-console-only. +- `presence`: `get → PresenceGetResult`, the complete current per-thread viewer and typing snapshot. - `plugins`: `applyUpdate → PluginApplyUpdateResult`, `callRpc → TOutput`, `checkUpdates/listUpdateResults → PluginCheckUpdatesResult`, `disable → PluginDisableResult`, `enable → PluginEnableResult`, `getSettings → PluginGetSettingsResult`, `getSource → PluginGetSourceResult`, `install/catalog.install → PluginInstallResult`, `list → PluginListResult`, `reload → PluginReloadResult`, `remove → PluginRemoveResult`, `token → PluginTokenResult`, `updateSettings → PluginUpdateSettingsResult`; nested catalog methods return the bundled plugin count or search results. - `projects`: `branches → ProjectBranchesResult`, `commands → ProjectCommandsResult`, `create → ProjectCreateResult`, `defaultExecutionOptions → ProjectDefaultExecutionOptionsResult`, `delete → ProjectDeleteResult`, `fileContent → ProjectFileContentResult`, `files → ProjectFilesResult`, `get → ProjectGetResult`, `list → ProjectListResult`, `paths → ProjectPathsResult`, `promptHistory → ProjectPromptHistoryResult`, `reorder → ProjectReorderResult`, `update → ProjectUpdateResult`; `attachments.read/upload → ProjectAttachmentReadResult/ProjectAttachmentUploadResult`; `sources.add/delete/update → ProjectSourceAddResult/ProjectSourceDeleteResult/ProjectSourceUpdateResult`. - `providers`: `list → ProviderListResult`; `models → ProviderModelsResult`. @@ -794,18 +796,18 @@ All names below are exported portable aliases (except the generic `TOutput`, con ### Multi-machine routing classifications and fallbacks -| Classification | SDK areas | Rule | -| ---------------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| explicit host resource | `hosts.*` | `hostId` is required; there is no fallback. | -| optional host primitive | `files.*` | optional `hostId`; omission selects the primary/local host. `rootPath` confines mutations and reads where offered. | -| environment-owned | `environments.*` | `environmentId` resolves the environment and its owning host/worktree; callers do not add a competing `hostId`. | -| project workspace union | `projects.commands/files/fileContent/paths` | exactly environment, explicit host, or neither; neither means the primary host's project source. | -| project creation/source | `projects.create`, `projects.sources.*` | local-path sources carry their owning `hostId`; clone/local source DTOs preserve explicit machine ownership. | -| client-local transfer | `projects.attachments.*`, `system.transcribeVoice` | bytes originate at the SDK client and are uploaded to the server; they are not paths read by the server or execution host. | -| provider discovery union | `providers.list/models` | exactly environment host, explicit host, or primary-host fallback. | -| thread-owned execution | `threads.*` | an existing thread routes through its environment/host; `spawn` may select an existing environment or creation host through its request contract, and plugin origin attribution is filled once by the plugin wrapper. | -| terminal discriminated scope | `terminals.list/create` | exactly thread, environment, or host-path; subsequent operations route from the server-owned terminal id. | -| server-global/admin | `plugins`, `system` settings/config, `theme`, `threadSections`, `status`, `guide` | runs against server-owned state; host selection appears only in method-specific DTOs such as usage/execution queries. | +| Classification | SDK areas | Rule | +| ---------------------------- | -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| explicit host resource | `hosts.*` | `hostId` is required; there is no fallback. | +| optional host primitive | `files.*` | optional `hostId`; omission selects the primary/local host. `rootPath` confines mutations and reads where offered. | +| environment-owned | `environments.*` | `environmentId` resolves the environment and its owning host/worktree; callers do not add a competing `hostId`. | +| project workspace union | `projects.commands/files/fileContent/paths` | exactly environment, explicit host, or neither; neither means the primary host's project source. | +| project creation/source | `projects.create`, `projects.sources.*` | local-path sources carry their owning `hostId`; clone/local source DTOs preserve explicit machine ownership. | +| client-local transfer | `projects.attachments.*`, `system.transcribeVoice` | bytes originate at the SDK client and are uploaded to the server; they are not paths read by the server or execution host. | +| provider discovery union | `providers.list/models` | exactly environment host, explicit host, or primary-host fallback. | +| thread-owned execution | `threads.*` | an existing thread routes through its environment/host; `spawn` may select an existing environment or creation host through its request contract, and plugin origin attribution is filled once by the plugin wrapper. | +| terminal discriminated scope | `terminals.list/create` | exactly thread, environment, or host-path; subsequent operations route from the server-owned terminal id. | +| server-global/admin | `members`, `presence`, `plugins`, `system` settings/config, `theme`, `threadSections`, `status`, `guide` | runs against server-owned state; host selection appears only in method-specific DTOs such as usage/execution queries. | Fallbacks are contract, not implementation accidents: primary-host fallback applies only where explicitly documented above. Disconnected/unknown explicit hosts fail; they do not silently reroute. An environment always keeps its owning machine. Browser and Node transports preserve the same DTO and routing semantics, while local-host auto-discovery is a Node convenience only. @@ -815,36 +817,36 @@ Plugins normally use the already-bound `bb.sdk`; they do not construct another c ### Node/root entry -| Export | Contract | -| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | -| `createNodeTransport(args?)` | creates an HTTP/realtime transport from `baseUrl?`, CLI config, fetch, explicit realtime URL, timeout, and websocket factory. | -| `createNodeBbSdk(args?)` | creates the full `BbSdk`; accepts transport args plus optional context. | -| `fetchLocalHostId(args?)` | asks the local daemon for its host id; returns `null` on any failure. | -| `createBbSdk({ transport, context? })` | constructs all SDK areas over a supplied transport. | -| `createHttpTransport(args)` | creates the shared typed HTTP transport. | -| `createRequestTimeoutFetch({ timeoutMs })` | wraps fetch so request and response-body timeout failures become `BbRequestTimeoutError`. | -| `createGuideArea()` | creates the static guide renderer. | -| `DEFAULT_BB_REQUEST_TIMEOUT_MS` | 75,000 ms. | -| `DEFAULT_THREAD_WAIT_TIMEOUT_MS` | 20 minutes. | -| `DEFAULT_THREAD_WAIT_POLL_INTERVAL_MS` | 250 ms. | -| `BbHttpError` | non-2xx error with `status` and nullable machine-readable `code`. | -| `BbRequestTimeoutError` | normalized request/body timeout error. | -| `ThreadWaitTimeoutError` | wait timeout with thread id and target. | -| `ThreadWaitUnreachableError` | status target cannot be reached by waiting alone. | -| public type exports | every area argument/result DTO, routing union, realtime event/subscription type, transport/context type, and `BbSdk`. | +| Export | Contract | +| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `createNodeTransport(args?)` | creates an HTTP/realtime transport from `baseUrl?`, CLI config, fetch, explicit realtime URL, optional `claimedIdentity`, timeout, and websocket factory. | +| `createNodeBbSdk(args?)` | creates the full `BbSdk`; accepts transport args, optional context, and optional `claimedIdentity`. | +| `fetchLocalHostId(args?)` | asks the local daemon for its host id; returns `null` on any failure. | +| `createBbSdk({ transport, context? })` | constructs all SDK areas over a supplied transport. | +| `createHttpTransport(args)` | creates the shared typed HTTP transport. | +| `createRequestTimeoutFetch({ timeoutMs })` | wraps fetch so request and response-body timeout failures become `BbRequestTimeoutError`. | +| `createGuideArea()` | creates the static guide renderer. | +| `DEFAULT_BB_REQUEST_TIMEOUT_MS` | 75,000 ms. | +| `DEFAULT_THREAD_WAIT_TIMEOUT_MS` | 20 minutes. | +| `DEFAULT_THREAD_WAIT_POLL_INTERVAL_MS` | 250 ms. | +| `BbHttpError` | non-2xx error with `status` and nullable machine-readable `code`. | +| `BbRequestTimeoutError` | normalized request/body timeout error. | +| `ThreadWaitTimeoutError` | wait timeout with thread id and target. | +| `ThreadWaitUnreachableError` | status target cannot be reached by waiting alone. | +| public type exports | every area argument/result DTO, routing union, realtime event/subscription type, transport/context type, and `BbSdk`. | Transport arguments default to CLI-configured `BB_SERVER_URL`, the standard 75-second timeout fetch, and a Node websocket factory. `timeoutMs` must be finite and non-negative; zero is permitted. ### Browser entry -| Export | Contract | -| ------------------------------- | ----------------------------------------------------------------------------------------------------------- | -| `createBrowserTransport(args?)` | creates browser HTTP/realtime transport from optional base URL, fetch, realtime URL, and websocket factory. | -| `createBrowserBbSdk(args?)` | creates the full `BbSdk`. | -| `bb` | default singleton created by `createBrowserBbSdk()`. | -| `createBbSdk` | core constructor. | -| `createHttpTransport` | transport constructor. | -| public type exports | the same portable area/DTO/realtime inventory as the root entry; only Node runtime helpers are omitted. | +| Export | Contract | +| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| `createBrowserTransport(args?)` | creates browser HTTP/realtime transport from optional base URL, fetch, realtime URL, `claimedIdentity`, and websocket factory. | +| `createBrowserBbSdk(args?)` | creates the full `BbSdk`; a claimed identity is encoded on HTTP and realtime connections. | +| `bb` | default singleton created by `createBrowserBbSdk()`. | +| `createBbSdk` | core constructor. | +| `createHttpTransport` | transport constructor. | +| public type exports | the same portable area/DTO/realtime inventory as the root entry; only Node runtime helpers are omitted. | ### `@bb/sdk/core` diff --git a/packages/bb-app/src/public-sdk.ts b/packages/bb-app/src/public-sdk.ts index 4a3bcc2ada..8c6f71c106 100644 --- a/packages/bb-app/src/public-sdk.ts +++ b/packages/bb-app/src/public-sdk.ts @@ -67,7 +67,9 @@ export class BBSdk implements BbSdk { readonly files: BbSdk["files"]; readonly guide: BbSdk["guide"]; readonly hosts: BbSdk["hosts"]; + readonly members: BbSdk["members"]; readonly plugins: BbSdk["plugins"]; + readonly presence: BbSdk["presence"]; readonly projects: BbSdk["projects"]; readonly providers: BbSdk["providers"]; readonly status: BbSdk["status"]; @@ -84,7 +86,9 @@ export class BBSdk implements BbSdk { this.files = sdk.files; this.guide = sdk.guide; this.hosts = sdk.hosts; + this.members = sdk.members; this.plugins = sdk.plugins; + this.presence = sdk.presence; this.projects = sdk.projects; this.providers = sdk.providers; this.status = sdk.status; diff --git a/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts b/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts index 24ae2e5c15..616bef1a71 100644 --- a/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts +++ b/packages/plugin-sdk/bundled-types/bb-plugin-sdk.d.ts @@ -792,8 +792,8 @@ declare const providerPendingInteractionSchema: z$1.ZodObject<{ id: z$1.ZodString; threadId: z$1.ZodString; status: z$1.ZodEnum<{ - pending: "pending"; interrupted: "interrupted"; + pending: "pending"; resolving: "resolving"; resolved: "resolved"; }>; @@ -930,8 +930,8 @@ declare const pluginPendingInteractionSchema: z$1.ZodObject<{ id: z$1.ZodString; threadId: z$1.ZodString; status: z$1.ZodEnum<{ - pending: "pending"; interrupted: "interrupted"; + pending: "pending"; resolving: "resolving"; resolved: "resolved"; }>; @@ -1074,8 +1074,8 @@ declare const threadEventSchema: z$1.ZodPipe; @@ -1119,10 +1119,10 @@ declare const threadEventSchema: z$1.ZodPipe; approvalStatus: z$1.ZodNullable; }, z$1.core.$strip>>; status: z$1.ZodEnum<{ - pending: "pending"; completed: "completed"; failed: "failed"; interrupted: "interrupted"; + pending: "pending"; }>; approvalStatus: z$1.ZodNullable>; status: z$1.ZodEnum<{ - pending: "pending"; completed: "completed"; failed: "failed"; interrupted: "interrupted"; + pending: "pending"; }>; result: z$1.ZodOptional; error: z$1.ZodOptional; @@ -1252,17 +1252,17 @@ declare const threadEventSchema: z$1.ZodPipe; taskStatus: z$1.ZodEnum<{ - pending: "pending"; - running: "running"; - paused: "paused"; completed: "completed"; failed: "failed"; + paused: "paused"; + pending: "pending"; + running: "running"; killed: "killed"; stopped: "stopped"; }>; @@ -1278,8 +1278,8 @@ declare const threadEventSchema: z$1.ZodPipe; approvalStatus: z$1.ZodNullable; }, z$1.core.$strip>>; status: z$1.ZodEnum<{ - pending: "pending"; completed: "completed"; failed: "failed"; interrupted: "interrupted"; + pending: "pending"; }>; approvalStatus: z$1.ZodNullable>; status: z$1.ZodEnum<{ - pending: "pending"; completed: "completed"; failed: "failed"; interrupted: "interrupted"; + pending: "pending"; }>; result: z$1.ZodOptional; error: z$1.ZodOptional; @@ -1480,17 +1480,17 @@ declare const threadEventSchema: z$1.ZodPipe; taskStatus: z$1.ZodEnum<{ - pending: "pending"; - running: "running"; - paused: "paused"; completed: "completed"; failed: "failed"; + paused: "paused"; + pending: "pending"; + running: "running"; killed: "killed"; stopped: "stopped"; }>; @@ -1506,8 +1506,8 @@ declare const threadEventSchema: z$1.ZodPipe; taskStatus: z$1.ZodEnum<{ - pending: "pending"; - running: "running"; - paused: "paused"; completed: "completed"; failed: "failed"; + paused: "paused"; + pending: "pending"; + running: "running"; killed: "killed"; stopped: "stopped"; }>; @@ -1635,8 +1635,8 @@ declare const threadEventSchema: z$1.ZodPipe; taskStatus: z$1.ZodEnum<{ - pending: "pending"; - running: "running"; - paused: "paused"; completed: "completed"; failed: "failed"; + paused: "paused"; + pending: "pending"; + running: "running"; killed: "killed"; stopped: "stopped"; }>; @@ -1707,8 +1707,8 @@ declare const threadEventSchema: z$1.ZodPipe>; }, z$1.core.$strip>>; explanation: z$1.ZodOptional; @@ -2186,8 +2186,8 @@ declare const threadEventSchema: z$1.ZodPipe; @@ -2238,8 +2238,8 @@ declare const threadEventSchema: z$1.ZodPipe; @@ -2409,8 +2409,8 @@ declare const threadTimelinePendingTodosSchema: z$1.ZodObject<{ id: z$1.ZodString; text: z$1.ZodString; status: z$1.ZodEnum<{ - pending: "pending"; completed: "completed"; + pending: "pending"; in_progress: "in_progress"; }>; }, z$1.core.$strip>>; @@ -2694,9 +2694,9 @@ declare const projectBranchesResponseSchema: z$1.ZodObject<{ selectedBranch: z$1.ZodNullable; }, z$1.core.$strip>>; defaultWorktreeBaseBranch: z$1.ZodNullable; @@ -3017,9 +3017,9 @@ declare const environmentDiffBranchesResponseSchema: z$1.ZodObject<{ selectedBranch: z$1.ZodNullable; }, z$1.core.$strip>>; }, z$1.core.$strip>; @@ -3104,8 +3104,8 @@ declare const environmentArchiveThreadsResponseSchema: z$1.ZodObject<{ type EnvironmentArchiveThreadsResponse = z$1.infer; declare const pullRequestMergeMethodSchema: z$1.ZodEnum<{ merge: "merge"; - squash: "squash"; rebase: "rebase"; + squash: "squash"; }>; type PullRequestMergeMethod = z$1.infer; declare const commitActionResponseSchema: z$1.ZodObject<{ @@ -3136,8 +3136,8 @@ declare const pullRequestMergeActionResponseSchema: z$1.ZodObject<{ action: z$1.ZodLiteral<"pull_request_merge">; method: z$1.ZodEnum<{ merge: "merge"; - squash: "squash"; rebase: "rebase"; + squash: "squash"; }>; message: z$1.ZodString; }, z$1.core.$strip>; @@ -3298,10 +3298,10 @@ declare const environmentPullRequestResponseSchema: z$1.ZodDiscriminatedUnion<[z mergeability: z$1.ZodObject<{ state: z$1.ZodEnum<{ unknown: "unknown"; - blocked: "blocked"; draft: "draft"; mergeable: "mergeable"; conflicts: "conflicts"; + blocked: "blocked"; }>; mergeStateStatus: z$1.ZodNullable; attention: z$1.ZodEnum<{ none: "none"; - blocked: "blocked"; 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"; @@ -3746,8 +3746,8 @@ declare const hostDaemonCommandRegistry: { }, z$1.core.$strict>], "kind">>; disallowedTools: z$1.ZodOptional>; instructionMode: z$1.ZodEnum<{ - replace: "replace"; append: "append"; + replace: "replace"; }>; type: z$1.ZodLiteral<"thread.start">; requestId: z$1.ZodString; @@ -4243,8 +4243,8 @@ declare const hostDaemonCommandRegistry: { }>; }, z$1.core.$strip>; instructionMode: z$1.ZodEnum<{ - replace: "replace"; append: "append"; + replace: "replace"; }>; projectId: z$1.ZodString; providerId: z$1.ZodString; @@ -5155,9 +5155,9 @@ declare const hostDaemonCommandRegistry: { executablePath: z$1.ZodNullable; installed: z$1.ZodBoolean; installSource: z$1.ZodEnum<{ + external: "external"; notInstalled: "notInstalled"; npmGlobal: "npmGlobal"; - external: "external"; }>; currentVersion: z$1.ZodNullable; latestVersion: z$1.ZodNullable; @@ -5330,13 +5330,13 @@ declare const hostDaemonCommandRegistry: { 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"; + unknown: "unknown"; }>; workspacePath: z$1.ZodString; message: z$1.ZodString; @@ -5380,13 +5380,13 @@ declare const hostDaemonCommandRegistry: { 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"; + unknown: "unknown"; }>; workspacePath: z$1.ZodString; message: z$1.ZodString; @@ -5442,13 +5442,13 @@ declare const hostDaemonCommandRegistry: { 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"; + unknown: "unknown"; }>; workspacePath: z$1.ZodString; message: z$1.ZodString; @@ -5490,13 +5490,13 @@ declare const hostDaemonCommandRegistry: { 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"; + unknown: "unknown"; }>; workspacePath: z$1.ZodString; message: z$1.ZodString; @@ -5614,9 +5614,9 @@ declare const providerCliStatusResponseSchema: z$1.ZodRecord; installed: z$1.ZodBoolean; installSource: z$1.ZodEnum<{ + external: "external"; notInstalled: "notInstalled"; npmGlobal: "npmGlobal"; - external: "external"; }>; currentVersion: z$1.ZodNullable; latestVersion: z$1.ZodNullable; @@ -5760,14 +5760,24 @@ type HostProviderCliStatusResponse = ProviderCliStatusResponse; type HostProviderCliInstallRequest = ProviderCliInstallRequest; type HostProviderCliInstallEvent = ProviderCliInstallEvent; +declare const memberSchema: z$1.ZodObject<{ + userId: z$1.ZodString; + handle: z$1.ZodString; + displayName: z$1.ZodString; + imageUrl: z$1.ZodNullable; + addedByUserId: z$1.ZodString; + createdAt: z$1.ZodNumber; +}, z$1.core.$strict>; +type Member = z$1.infer; + 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"; - unavailable: "unavailable"; }>; devMode: z$1.ZodOptional>; installed: z$1.ZodObject<{ @@ -5834,11 +5844,11 @@ declare const installedPluginSchema: z$1.ZodObject<{ sourceDisplay: z$1.ZodString; updateState: z$1.ZodObject<{ outcome: z$1.ZodOptional>; availableVersion: z$1.ZodOptional; blockedVersion: z$1.ZodOptional; @@ -5857,8 +5867,8 @@ declare const installedPluginSchema: z$1.ZodObject<{ status: z$1.ZodEnum<{ error: "error"; running: "running"; - incompatible: "incompatible"; missing: "missing"; + incompatible: "incompatible"; disabled: "disabled"; degraded: "degraded"; "needs-configuration": "needs-configuration"; @@ -5927,11 +5937,11 @@ declare const pluginListResponseSchema: z$1.ZodObject<{ sourceDisplay: z$1.ZodString; updateState: z$1.ZodObject<{ outcome: z$1.ZodOptional>; availableVersion: z$1.ZodOptional; blockedVersion: z$1.ZodOptional; @@ -5950,8 +5960,8 @@ declare const pluginListResponseSchema: z$1.ZodObject<{ status: z$1.ZodEnum<{ error: "error"; running: "running"; - incompatible: "incompatible"; missing: "missing"; + incompatible: "incompatible"; disabled: "disabled"; degraded: "degraded"; "needs-configuration": "needs-configuration"; @@ -6021,11 +6031,11 @@ declare const pluginReloadResponseSchema: z$1.ZodObject<{ sourceDisplay: z$1.ZodString; updateState: z$1.ZodObject<{ outcome: z$1.ZodOptional>; availableVersion: z$1.ZodOptional; blockedVersion: z$1.ZodOptional; @@ -6044,8 +6054,8 @@ declare const pluginReloadResponseSchema: z$1.ZodObject<{ status: z$1.ZodEnum<{ error: "error"; running: "running"; - incompatible: "incompatible"; missing: "missing"; + incompatible: "incompatible"; disabled: "disabled"; degraded: "degraded"; "needs-configuration": "needs-configuration"; @@ -6152,6 +6162,23 @@ declare const pluginCatalogSearchResultSchema: z$1.ZodObject<{ }, z$1.core.$strip>; type PluginCatalogSearchResult$1 = z$1.infer; +/** + * Complete current ephemeral viewer rosters, keyed by thread id. + * + * Unlike this HTTP snapshot, realtime `presence-summary` messages are partial + * patches: merge each supplied thread entry into the local summary, and remove + * an entry when its supplied handle array is empty. + */ +declare const presenceSnapshotResponseSchema: z$1.ZodObject<{ + threads: z$1.ZodRecord; + typing: z$1.ZodBoolean; + }, z$1.core.$strict>>>>; +}, z$1.core.$strict>; +type PresenceSnapshotResponse = z$1.infer; + declare const systemExecutionOptionsResponseSchema: z$1.ZodObject<{ providers: z$1.ZodArray; exitCode: z$1.ZodNullable; @@ -6655,9 +6682,9 @@ declare const terminalListResponseSchema: z$1.ZodObject<{ cols: z$1.ZodNumber; rows: z$1.ZodNumber; status: z$1.ZodEnum<{ - running: "running"; starting: "starting"; disconnected: "disconnected"; + running: "running"; exited: "exited"; }>; exitCode: z$1.ZodNullable; @@ -9032,8 +9059,8 @@ declare const threadTimelineResponseSchema: z$1.ZodObject<{ updatedAt: z$1.ZodNumber; objective: z$1.ZodString; status: z$1.ZodEnum<{ - paused: "paused"; active: "active"; + paused: "paused"; budgetLimited: "budgetLimited"; complete: "complete"; }>; @@ -9518,6 +9545,28 @@ interface HostsArea { update(args: HostUpdateArgs): Promise; } +interface MemberAddArgs { + handle: string; +} +interface MemberRemoveArgs { + handle: string; +} +type MemberListResult = Member[]; +type MemberAddResult = Member; +type MemberRemoveResult = { + ok: true; +}; +interface MembersArea { + add(args: MemberAddArgs): Promise; + list(): Promise; + remove(args: MemberRemoveArgs): Promise; +} + +type PresenceGetResult = PresenceSnapshotResponse; +interface PresenceArea { + get(): Promise; +} + interface ProjectListArgs { include?: ProjectListQuery["include"]; /** Include the singleton personal project. Defaults to false for compatibility. */ @@ -10363,6 +10412,8 @@ interface BbSdk extends BbRealtime { files: FilesArea; guide: GuideArea; hosts: HostsArea; + members: MembersArea; + presence: PresenceArea; projects: ProjectsArea; plugins: PluginsArea; providers: ProvidersArea; diff --git a/packages/sdk/src/areas/members.ts b/packages/sdk/src/areas/members.ts new file mode 100644 index 0000000000..cde41e2e0b --- /dev/null +++ b/packages/sdk/src/areas/members.ts @@ -0,0 +1,42 @@ +import type { Member } from "@bb/server-contract"; +import type { CreateSdkAreaArgs } from "./common.js"; + +export interface MemberAddArgs { + handle: string; +} + +export interface MemberRemoveArgs { + handle: string; +} + +export type MemberListResult = Member[]; +export type MemberAddResult = Member; +export type MemberRemoveResult = { ok: true }; + +export interface MembersArea { + add(args: MemberAddArgs): Promise; + list(): Promise; + remove(args: MemberRemoveArgs): Promise; +} + +export function createMembersArea(args: CreateSdkAreaArgs): MembersArea { + const { transport } = args; + return { + async add(input) { + return transport.readJson( + transport.api.v1.members.$post({ json: { handle: input.handle } }), + ); + }, + async list() { + const response = await transport.readJson( + transport.api.v1.members.$get({}), + ); + return response.members; + }, + async remove(input) { + return transport.readJson( + transport.api.v1.members.$delete({ json: { handle: input.handle } }), + ); + }, + }; +} diff --git a/packages/sdk/src/areas/presence.ts b/packages/sdk/src/areas/presence.ts new file mode 100644 index 0000000000..4c62afb924 --- /dev/null +++ b/packages/sdk/src/areas/presence.ts @@ -0,0 +1,16 @@ +import type { PresenceSnapshotResponse } from "@bb/server-contract"; +import type { CreateSdkAreaArgs } from "./common.js"; + +export type PresenceGetResult = PresenceSnapshotResponse; + +export interface PresenceArea { + get(): Promise; +} + +export function createPresenceArea(args: CreateSdkAreaArgs): PresenceArea { + return { + get() { + return args.transport.readJson(args.transport.api.v1.presence.$get({})); + }, + }; +} diff --git a/packages/sdk/src/browser.ts b/packages/sdk/src/browser.ts index 1484df49a9..fcfb2427b1 100644 --- a/packages/sdk/src/browser.ts +++ b/packages/sdk/src/browser.ts @@ -1,4 +1,5 @@ import { createBbSdk, type BbSdk } from "./core.js"; +import type { ClaimedIdentity } from "@bb/domain"; import { createHttpTransport } from "./transport-http.js"; import type { BbRealtimeSocketFactory, @@ -8,6 +9,7 @@ import type { export interface CreateBrowserTransportArgs { baseUrl?: string; + claimedIdentity?: ClaimedIdentity; fetch?: typeof fetch; realtimeUrl?: string; websocket?: BbRealtimeSocketFactory; @@ -22,6 +24,7 @@ export function createBrowserTransport( ): BbSdkTransport { return createHttpTransport({ baseUrl: args.baseUrl, + ...(args.claimedIdentity ? { claimedIdentity: args.claimedIdentity } : {}), fetch: args.fetch, realtimeUrl: args.realtimeUrl, runtime: "browser", diff --git a/packages/sdk/src/core.ts b/packages/sdk/src/core.ts index 408b71ea08..b0caba7317 100644 --- a/packages/sdk/src/core.ts +++ b/packages/sdk/src/core.ts @@ -6,6 +6,8 @@ import { import { createFilesArea, type FilesArea } from "./areas/files.js"; import { createGuideArea, type GuideArea } from "./areas/guide.js"; import { createHostsArea, type HostsArea } from "./areas/hosts.js"; +import { createMembersArea, type MembersArea } from "./areas/members.js"; +import { createPresenceArea, type PresenceArea } from "./areas/presence.js"; import { createProjectsArea, type ProjectsArea } from "./areas/projects.js"; import { createProvidersArea, type ProvidersArea } from "./areas/providers.js"; import { createPluginsArea, type PluginsArea } from "./areas/plugins.js"; @@ -33,6 +35,8 @@ export interface BbSdk extends BbRealtime { files: FilesArea; guide: GuideArea; hosts: HostsArea; + members: MembersArea; + presence: PresenceArea; projects: ProjectsArea; plugins: PluginsArea; providers: ProvidersArea; @@ -55,6 +59,8 @@ export function createBbSdk(args: CreateBbSdkArgs): BbSdk { files: createFilesArea(sdkContext), guide: createGuideArea(), hosts: createHostsArea(sdkContext), + members: createMembersArea(sdkContext), + presence: createPresenceArea(sdkContext), subscribe(args) { return realtime.subscribe(args); }, diff --git a/packages/sdk/src/node.ts b/packages/sdk/src/node.ts index 684e819d27..81fba0e7c3 100644 --- a/packages/sdk/src/node.ts +++ b/packages/sdk/src/node.ts @@ -1,4 +1,5 @@ import { loadCliConfig, type CliConfig } from "@bb/config/cli"; +import type { ClaimedIdentity } from "@bb/domain"; import { createHostDaemonLocalClient, DEFAULT_HOST_DAEMON_LOCAL_BIND_HOST, @@ -19,6 +20,7 @@ import type { export interface CreateNodeTransportArgs { baseUrl?: string; + claimedIdentity?: ClaimedIdentity; cliConfig?: CliConfig; fetch?: FetchImplementation; realtimeUrl?: string; @@ -51,6 +53,7 @@ export function createNodeTransport( // Only fall back to CLI config when no base URL is given, so explicitly // configured SDKs work in environments without BB_SERVER_URL. baseUrl: args.baseUrl ?? resolveCliConfig(args.cliConfig).BB_SERVER_URL, + ...(args.claimedIdentity ? { claimedIdentity: args.claimedIdentity } : {}), fetch: args.fetch ?? createRequestTimeoutFetch({ diff --git a/packages/sdk/src/public-types.ts b/packages/sdk/src/public-types.ts index 3eb352b9d8..b859eaa18f 100644 --- a/packages/sdk/src/public-types.ts +++ b/packages/sdk/src/public-types.ts @@ -26,6 +26,8 @@ export type * from "./areas/environments.js"; export type * from "./areas/files.js"; export type * from "./areas/guide.js"; export type * from "./areas/hosts.js"; +export type * from "./areas/members.js"; +export type * from "./areas/presence.js"; export type * from "./areas/plugins.js"; export type * from "./areas/projects.js"; export type * from "./areas/providers.js"; diff --git a/packages/sdk/src/realtime-url.ts b/packages/sdk/src/realtime-url.ts index b2a2b24622..6ab72200c0 100644 --- a/packages/sdk/src/realtime-url.ts +++ b/packages/sdk/src/realtime-url.ts @@ -57,28 +57,37 @@ function browserSameOriginRealtimeUrl(): string | null { export function resolveRealtimeUrl(args: ResolveRealtimeUrlArgs): string { const { transport } = args; + let resolved: string; if (transport.realtimeUrl) { - return transport.realtimeUrl; - } - - // Mirror the HTTP transport's derivation (`${baseUrl}/api/v1${path}`): a - // path-prefixed baseUrl keeps its prefix for the websocket endpoint too. - const absoluteBaseUrl = absoluteHttpBaseUrl(transport.baseUrl); - if (absoluteBaseUrl) { - return websocketUrlFromHttpUrl({ - preservePathPrefix: true, - url: absoluteBaseUrl, - }); - } - - if (transport.runtime === "browser") { - const sameOriginUrl = browserSameOriginRealtimeUrl(); - if (sameOriginUrl) { - return sameOriginUrl; + resolved = transport.realtimeUrl; + } else { + // Mirror the HTTP transport's derivation (`${baseUrl}/api/v1${path}`): a + // path-prefixed baseUrl keeps its prefix for the websocket endpoint too. + const absoluteBaseUrl = absoluteHttpBaseUrl(transport.baseUrl); + if (absoluteBaseUrl) { + resolved = websocketUrlFromHttpUrl({ + preservePathPrefix: true, + url: absoluteBaseUrl, + }); + } else if (transport.runtime === "browser") { + const sameOriginUrl = browserSameOriginRealtimeUrl(); + if (!sameOriginUrl) { + throw new Error( + "BB SDK realtime requires an absolute baseUrl or realtimeUrl in this runtime.", + ); + } + resolved = sameOriginUrl; + } else { + throw new Error( + "BB SDK realtime requires an absolute baseUrl or realtimeUrl in this runtime.", + ); } } - throw new Error( - "BB SDK realtime requires an absolute baseUrl or realtimeUrl in this runtime.", - ); + if (transport.claimedIdentityHeader) { + const url = new URL(resolved); + url.searchParams.set("identity", transport.claimedIdentityHeader); + return url.href; + } + return resolved; } diff --git a/packages/sdk/src/transport-http.ts b/packages/sdk/src/transport-http.ts index 71dbfd9ee7..954aa59046 100644 --- a/packages/sdk/src/transport-http.ts +++ b/packages/sdk/src/transport-http.ts @@ -1,13 +1,15 @@ import { createApiClient } from "@bb/server-contract"; +import { + CLAIMED_IDENTITY_HEADER, + encodeClaimedIdentityHeader, +} from "@bb/domain"; import { readJsonResponse, readVoidResponse, resolveResponse, } from "./response.js"; -import type { - BbSdkTransport, - CreateHttpTransportArgs, -} from "./transport.js"; +import type { BbSdkTransport, CreateHttpTransportArgs } from "./transport.js"; +import type { FetchImplementation } from "./response.js"; const SAME_ORIGIN_BASE_URL = ""; @@ -15,12 +17,28 @@ export function createHttpTransport( args: CreateHttpTransportArgs, ): BbSdkTransport { const baseUrl = args.baseUrl ?? SAME_ORIGIN_BASE_URL; - const fetchImpl = args.fetch ?? fetch; + const baseFetch = args.fetch ?? fetch; + const claimedIdentityHeader = args.claimedIdentity + ? encodeClaimedIdentityHeader(args.claimedIdentity) + : undefined; + const fetchImpl: FetchImplementation = claimedIdentityHeader + ? (input, init) => { + const headers = new Headers( + input instanceof Request ? input.headers : undefined, + ); + new Headers(init?.headers).forEach((value, name) => { + headers.set(name, value); + }); + headers.set(CLAIMED_IDENTITY_HEADER, claimedIdentityHeader); + return baseFetch(input, { ...init, headers }); + } + : baseFetch; const client = createApiClient(baseUrl, { fetch: fetchImpl }); return { api: client.api, baseUrl, + ...(claimedIdentityHeader ? { claimedIdentityHeader } : {}), fetch: fetchImpl, ...(args.realtimeUrl ? { realtimeUrl: args.realtimeUrl } : {}), runtime: args.runtime, diff --git a/packages/sdk/src/transport.ts b/packages/sdk/src/transport.ts index 24df4cc923..1f02652c79 100644 --- a/packages/sdk/src/transport.ts +++ b/packages/sdk/src/transport.ts @@ -1,14 +1,13 @@ import type { ApiClient } from "@bb/server-contract"; -import type { - FetchImplementation, - JsonBodyOf, -} from "./response.js"; +import type { ClaimedIdentity } from "@bb/domain"; +import type { FetchImplementation, JsonBodyOf } from "./response.js"; export type BbSdkRuntime = "node" | "browser"; export interface BbSdkTransport { api: ApiClient["api"]; baseUrl: string; + claimedIdentityHeader?: string; fetch: FetchImplementation; realtimeUrl?: string; runtime: BbSdkRuntime; @@ -54,6 +53,7 @@ export interface BbSdkContext {} export interface CreateHttpTransportArgs { baseUrl?: string; + claimedIdentity?: ClaimedIdentity; fetch?: FetchImplementation; realtimeUrl?: string; runtime: BbSdkRuntime; diff --git a/packages/sdk/test/public-types.test.ts b/packages/sdk/test/public-types.test.ts index e2d8077b03..a2348863d2 100644 --- a/packages/sdk/test/public-types.test.ts +++ b/packages/sdk/test/public-types.test.ts @@ -223,6 +223,8 @@ type ExpectedBbSdkKey = | "files" | "guide" | "hosts" + | "members" + | "presence" | "plugins" | "projects" | "providers" diff --git a/packages/sdk/test/sdk.test.ts b/packages/sdk/test/sdk.test.ts index bbb5f10909..5894f1e181 100644 --- a/packages/sdk/test/sdk.test.ts +++ b/packages/sdk/test/sdk.test.ts @@ -1,10 +1,16 @@ import { describe, expect, it } from "vitest"; import { z } from "zod"; -import type { Environment, JsonValue } from "@bb/domain"; +import { + CLAIMED_IDENTITY_HEADER, + encodeClaimedIdentityHeader, + type Environment, + type JsonValue, +} from "@bb/domain"; import { createBbSdk } from "../src/core.js"; import { createHttpTransport } from "../src/transport-http.js"; import { ThreadWaitTimeoutError } from "../src/areas/threads.js"; import type { FetchImplementation } from "../src/response.js"; +import { resolveRealtimeUrl } from "../src/realtime-url.js"; interface CapturedRequest { bodyText: string | undefined; @@ -103,6 +109,107 @@ function createFetchQueue( } describe("@bb/sdk", () => { + it("lists, adds, and removes Connect members through the members area", async () => { + const member = { + userId: "user-1", + handle: "collaborator", + displayName: "Collaborator", + imageUrl: null, + addedByUserId: "owner-1", + createdAt: 123, + }; + const queue = createFetchQueue([ + { body: { members: [member] } }, + { body: member, status: 201 }, + { body: { ok: true } }, + ]); + const sdk = createBbSdk({ + transport: createHttpTransport({ + baseUrl: "http://bb.test", + fetch: queue.fetch, + runtime: "node", + }), + }); + + await expect(sdk.members.list()).resolves.toEqual([member]); + await expect(sdk.members.add({ handle: "collaborator" })).resolves.toEqual( + member, + ); + await expect( + sdk.members.remove({ handle: "collaborator" }), + ).resolves.toEqual({ ok: true }); + expect(queue.requests).toEqual([ + { + bodyText: undefined, + method: "GET", + url: "http://bb.test/api/v1/members", + }, + { + bodyText: JSON.stringify({ handle: "collaborator" }), + method: "POST", + url: "http://bb.test/api/v1/members", + }, + { + bodyText: JSON.stringify({ handle: "collaborator" }), + method: "DELETE", + url: "http://bb.test/api/v1/members", + }, + ]); + }); + + it("gets the complete presence snapshot", async () => { + const snapshot = { + threads: { + "thread-1": [ + { + handle: "collaborator", + displayName: "Collaborator", + imageUrl: null, + typing: true, + }, + ], + }, + }; + const queue = createFetchQueue([{ body: snapshot }]); + const sdk = createBbSdk({ + transport: createHttpTransport({ + baseUrl: "http://bb.test", + fetch: queue.fetch, + runtime: "node", + }), + }); + + await expect(sdk.presence.get()).resolves.toEqual(snapshot); + expect(queue.requests[0]?.url).toBe("http://bb.test/api/v1/presence"); + }); + + it("sets claimed identity on HTTP and realtime transports", async () => { + const identity = { + handle: "collaborator", + displayName: "Collaborator", + imageUrl: null, + clientId: "cli-1", + }; + let receivedHeaders: Headers | undefined; + const transport = createHttpTransport({ + baseUrl: "https://bb.test", + claimedIdentity: identity, + fetch: async (_input, init) => { + receivedHeaders = new Headers(init?.headers); + return jsonResponse({ body: { threads: {} } }); + }, + runtime: "node", + }); + const sdk = createBbSdk({ transport }); + + await sdk.presence.get(); + const encoded = encodeClaimedIdentityHeader(identity); + expect(receivedHeaders?.get(CLAIMED_IDENTITY_HEADER)).toBe(encoded); + expect(resolveRealtimeUrl({ transport })).toBe( + `wss://bb.test/ws?identity=${encodeURIComponent(encoded)}`, + ); + }); + it("sends thread pane presentation actions through the typed transport", async () => { const queue = createFetchQueue([{ body: { delivered: 3 } }]); const sdk = createBbSdk({ diff --git a/packages/server-contract/src/api-types.ts b/packages/server-contract/src/api-types.ts index ddb1d65d0f..2915efc45c 100644 --- a/packages/server-contract/src/api-types.ts +++ b/packages/server-contract/src/api-types.ts @@ -3,6 +3,7 @@ export * from "./api/projects.js"; export * from "./api/environments.js"; export * from "./api/files.js"; export * from "./api/hosts.js"; +export * from "./api/members.js"; export * from "./api/plugins.js"; export * from "./api/presence.js"; export * from "./api/system.js"; diff --git a/packages/server-contract/src/api/members.ts b/packages/server-contract/src/api/members.ts new file mode 100644 index 0000000000..7771cacade --- /dev/null +++ b/packages/server-contract/src/api/members.ts @@ -0,0 +1,26 @@ +import { z } from "zod"; + +export const memberSchema = z + .object({ + userId: z.string().min(1), + handle: z.string().min(1), + displayName: z.string().min(1), + imageUrl: z.string().nullable(), + addedByUserId: z.string().min(1), + createdAt: z.number().int().nonnegative(), + }) + .strict(); +export type Member = z.infer; + +export const memberListResponseSchema = z + .object({ members: z.array(memberSchema) }) + .strict(); +export type MemberListResponse = z.infer; + +export const addMemberRequestSchema = z + .object({ handle: z.string().trim().min(1).max(64) }) + .strict(); +export type AddMemberRequest = z.infer; + +export const removeMemberRequestSchema = addMemberRequestSchema; +export type RemoveMemberRequest = z.infer; diff --git a/packages/server-contract/src/public-api.ts b/packages/server-contract/src/public-api.ts index d339d1ae8a..fe33db7e3e 100644 --- a/packages/server-contract/src/public-api.ts +++ b/packages/server-contract/src/public-api.ts @@ -101,6 +101,10 @@ import type { HostProviderCliInstallEvent, HostProviderCliInstallRequest, HostProviderCliStatusResponse, + AddMemberRequest, + Member, + MemberListResponse, + RemoveMemberRequest, ProjectAttachmentContentQuery, ProjectAttachmentUploadForm, ProjectBranchesQuery, @@ -228,6 +232,8 @@ import { hostPickFolderRequestSchema, hostPathsExistRequestSchema, hostProviderCliInstallRequestSchema, + addMemberRequestSchema, + removeMemberRequestSchema, projectAttachmentContentQuerySchema, projectBranchesQuerySchema, projectCommandsQuerySchema, @@ -1185,6 +1191,31 @@ export const publicApiRoutes = { }), }, + members: { + list: defineRoute({ + path: "/members", + method: "get", + request: noRequest(), + response: jsonResponse(), + }), + add: defineRoute({ + path: "/members", + method: "post", + request: jsonRequest( + addMemberRequestSchema, + ), + response: jsonResponse({ status: 201 }), + }), + remove: defineRoute({ + path: "/members", + method: "delete", + request: jsonRequest( + removeMemberRequestSchema, + ), + response: jsonResponse<{ ok: true }>(), + }), + }, + system: { attention: defineRoute({ path: "/system/attention", diff --git a/packages/templates/src/generated/plugin-sdk-dts.generated.ts b/packages/templates/src/generated/plugin-sdk-dts.generated.ts index 7bf12ff392..b7cd21be09 100644 --- a/packages/templates/src/generated/plugin-sdk-dts.generated.ts +++ b/packages/templates/src/generated/plugin-sdk-dts.generated.ts @@ -2,6 +2,6 @@ // Generated by packages/templates/scripts/generate-templates.mjs from // @bb/plugin-sdk/bundled-types. Do not edit directly. -export const PLUGIN_SDK_DTS = "// Portable type declarations for `@bb/plugin-sdk`. Unpublished BB\n// workspace contracts are flattened; public subpaths may reuse the\n// package root without requiring any other @bb/* package.\n//\n// Confused by the API, or need a symbol that isn't here? Clone the BB repo\n// and read the real source: https://github.com/ymichael/bb\n\nimport { ComponentType } from 'react';\nimport Database from 'better-sqlite3';\nimport { Context } from 'hono';\nimport * as z from 'zod';\nimport { z as z$1 } from 'zod';\n\n/**\n * A value that survives a JSON round trip without coercion or data loss.\n *\n * Host boundaries still validate values at runtime because TypeScript cannot\n * exclude non-finite numbers and plugin bundles can bypass static types.\n */\ntype JsonValue$1 = string | number | boolean | null | JsonValue$1[] | {\n [key: string]: JsonValue$1;\n};\n\n/** A JSON-safe path segment reported by a Standard Schema validation issue. */\ntype PluginRpcIssuePathSegment = string | number;\n/** Validator-neutral validation detail carried by an RPC error envelope. */\ninterface PluginRpcValidationIssue {\n message: string;\n path?: PluginRpcIssuePathSegment[];\n}\n/** Stable wire error categories for plugin RPC. */\ntype PluginRpcErrorCode = \"invalid_json\" | \"invalid_input\" | \"handler_error\" | \"invalid_output\" | \"non_json_result\" | \"unknown_method\";\n/** Structured RPC failure returned as `{ ok: false, error }`. */\ninterface PluginRpcError {\n code: PluginRpcErrorCode;\n message: string;\n issues?: PluginRpcValidationIssue[];\n}\n/**\n * The validator-neutral subset of Standard Schema v1 used by plugin RPC.\n * Zod 4 schemas implement this interface directly; other validators can do\n * the same without becoming part of BB's public protocol.\n */\ninterface StandardSchemaV1 {\n readonly \"~standard\": {\n readonly version: 1;\n readonly vendor: string;\n readonly validate: (value: unknown) => StandardSchemaV1Result | Promise>;\n readonly types?: {\n readonly input: Input;\n readonly output: Output;\n };\n };\n}\ntype StandardSchemaV1Result = {\n readonly value: Output;\n readonly issues?: undefined;\n} | {\n readonly issues: readonly StandardSchemaV1Issue[];\n};\ninterface StandardSchemaV1Issue {\n readonly message: string;\n readonly path?: PropertyKey | readonly (PropertyKey | {\n readonly key: PropertyKey;\n })[];\n}\ntype StandardSchemaV1InferInput = NonNullable[\"input\"];\ntype StandardSchemaV1InferOutput = NonNullable[\"output\"];\ninterface PluginRpcMethodContract {\n readonly input: InputSchema;\n readonly output: OutputSchema;\n}\ntype PluginRpcContract = Readonly>;\n/** Define a shared RPC contract while preserving exact method/schema types. */\ndeclare function defineRpcContract(contract: Contract): Contract;\ntype PluginRpcHandlers = {\n [Method in keyof Contract]: (input: StandardSchemaV1InferOutput) => StandardSchemaV1InferInput | Promise>;\n};\ntype PluginRpcCallInput = StandardSchemaV1InferInput;\ntype PluginRpcCallArgs = null extends PluginRpcCallInput ? [input?: PluginRpcCallInput] : [input: PluginRpcCallInput];\ntype PluginRpcResult = StandardSchemaV1InferOutput;\n\n/**\n * The `@bb/plugin-sdk/app` contract (plugin design §5.2) — pure types with no\n * side effects. The BB app imports these to keep its real implementation in\n * sync (`satisfies PluginSdkApp`). Plugin authors import the same shapes through\n * `@bb/plugin-sdk/app`.\n *\n * Per-slot props are versioned contracts: additive-only within an SDK major.\n */\n/** Props passed to a `homepageSection` component. */\ninterface PluginHomepageSectionProps {\n /** Project in view on the compose surface; null when none is selected. */\n projectId: string | null;\n}\n/**\n * Props passed to a `settingsSection` component.\n *\n * Deliberately empty in V1; versioned additive like the other slot props.\n */\ninterface PluginSettingsSectionProps {\n}\n/** Props passed to a `navPanel` component (it owns its whole route). */\ninterface PluginNavPanelProps {\n /**\n * The route remainder after the panel root, \"\" at the root. The panel's\n * route is `/plugins///*`, so a deep link like\n * `/plugins/notes/notes/work/ideas.md` renders the panel with\n * `subPath: \"work/ideas.md\"`. Navigate within the panel via\n * `useBbNavigate().toPluginPanel(path, { subPath })` — browser\n * back/forward then walks panel-internal history.\n */\n subPath: string;\n}\n/** Props passed to a panel tab opened by a `threadPanelAction`. */\ninterface PluginThreadPanelProps {\n threadId: string;\n /**\n * The JSON value the action's `openPanel` call passed (round-tripped\n * through persistence, so the tab restores across reloads); null when the\n * action opened the panel without params.\n */\n params: JsonValue$1 | null;\n}\n/** Props passed to a `composerAccessory` component. */\ninterface PluginComposerAccessoryProps {\n projectId: string | null;\n threadId: string | null;\n}\ninterface PluginPendingInteractionView {\n id: string;\n threadId: string;\n title: string;\n payload: JsonValue$1;\n createdAt: number;\n expiresAt: number | null;\n}\ninterface PluginPendingInteractionProps {\n interaction: PluginPendingInteractionView;\n submit(value: JsonValue$1): Promise;\n cancel(): Promise;\n}\n/**\n * Props for a `sidebarFooterAction` — host-rendered (no plugin component).\n * Deliberately empty; the registration's `run` carries the behavior.\n */\ninterface PluginSidebarFooterActionProps {\n}\n/**\n * Where a file being opened by a `fileOpener` lives. `path` semantics follow\n * the source: workspace paths are relative to the environment's worktree,\n * thread-storage paths are relative to the thread's storage root, host paths\n * are absolute on the thread's host.\n */\ninterface PluginFileOpenerSource {\n kind: \"workspace\" | \"host\" | \"thread-storage\";\n threadId: string | null;\n environmentId: string | null;\n projectId: string | null;\n}\n/** Props passed to a `fileOpener` component (rendered as a panel file tab). */\ninterface PluginFileOpenerProps {\n path: string;\n source: PluginFileOpenerSource;\n}\n/**\n * Message context passed to a `messageDirective` component — the assistant\n * (or nested agent) message that contained the directive.\n */\ninterface PluginMessageDirectiveMessage {\n id: string;\n threadId: string;\n turnId: string | null;\n projectId: string | null;\n}\n/**\n * Open a worktree-relative file in the host's workspace file viewer. Returns\n * true when the host accepted the path; false when the path is invalid or the\n * viewer declined it.\n */\ntype PluginMessageDirectiveOpenWorkspaceFile = (path: string) => boolean;\ninterface PluginMessageDirectiveThreadPanelOptions {\n /** A `threadPanelAction` id registered by this same plugin. */\n actionId: string;\n title?: string;\n params?: JsonValue$1;\n}\n/** Open this plugin's registered action in the current thread side panel. */\ntype PluginMessageDirectiveOpenThreadPanel = (options: PluginMessageDirectiveThreadPanelOptions) => boolean;\n/**\n * Props passed to a `messageDirective` component. Attributes are untrusted\n * strings parsed from the directive; the plugin validates its own fields.\n */\ninterface PluginMessageDirectiveProps {\n /** Parsed, untrusted directive attributes (e.g. `{ file: \"demo.html\" }`). */\n attributes: Readonly>;\n /** Original directive source text (useful for diagnostics / crash fallback). */\n source: string;\n message: PluginMessageDirectiveMessage;\n /**\n * Opens a worktree-relative file in the host's workspace file viewer. Null\n * when the message surface has no workspace viewer available.\n */\n openWorkspaceFile: PluginMessageDirectiveOpenWorkspaceFile | null;\n /**\n * Opens one of this plugin's own `threadPanelAction` components in the\n * current thread side panel. Omitted by older hosts; null on message\n * surfaces without a thread panel.\n */\n openThreadPanel?: PluginMessageDirectiveOpenThreadPanel | null;\n}\ninterface PluginHomepageSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n component: ComponentType;\n}\ninterface PluginSettingsSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Optional host-rendered section heading. */\n title?: string;\n /**\n * Optional one-line host-rendered subheading under `title`, in the built-in\n * SettingsSection idiom (ignored when `title` is absent).\n */\n description?: string;\n component: ComponentType;\n}\ninterface PluginNavPanelRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /** URL segment under `/plugins//`; letters, digits, `-`, `_`. */\n path: string;\n component: ComponentType;\n /**\n * Optional component rendered on the right side of the shared title bar\n * (e.g. a sync button or a count). Contained separately from the body: a\n * throwing headerContent is hidden without breaking the title bar.\n */\n headerContent?: ComponentType;\n}\n/** Context handed to a `threadPanelAction`'s `run`. */\ninterface PluginThreadPanelActionContext {\n /** The thread whose panel launcher invoked the action. */\n threadId: string;\n /**\n * Open a tab in the thread's side panel rendering this action's\n * `component`. `title` labels the tab (default: the action's `title`);\n * `params` must be JSON-serializable — it is persisted with the tab and\n * reaches the component as its `params` prop. Opening with params\n * identical to an already-open tab of this action focuses that tab\n * (updating its title) instead of duplicating it. May be called more than\n * once (different params ⇒ multiple tabs) or not at all.\n */\n openPanel(options?: {\n title?: string;\n params?: JsonValue$1;\n }): void;\n}\ninterface PluginThreadPanelActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label of the action row in the panel's new-tab launcher. */\n title: string;\n /**\n * Icon hint (BB icon name) used when the plugin ships no logo; the\n * launcher row and opened tabs prefer the plugin's logo.\n */\n icon?: string;\n /** Rendered inside every panel tab this action opens. */\n component: ComponentType;\n /**\n * Runs when the user activates the action: call your RPC methods, show a\n * toast, and/or open panel tabs via `context.openPanel`. Omitted =\n * immediately open a panel tab with defaults. Errors (sync or async) are\n * contained and logged; they never break the launcher.\n */\n run?(context: PluginThreadPanelActionContext): void | Promise;\n}\ninterface PluginComposerAccessoryRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n component: ComponentType;\n}\ninterface PluginPendingInteractionRegistration {\n /** Matches `rendererId` passed to `bb.ui.requestInput`. */\n id: string;\n component: ComponentType;\n}\n/** Context handed to a `sidebarFooterAction`'s `run`. */\ninterface PluginSidebarFooterActionContext {\n /**\n * Navigate to this plugin's Settings detail page\n * (`/settings/plugins/`), where declarative settings and\n * `settingsSection` slots render.\n */\n openSettings(): void;\n}\n/**\n * An icon button in the app sidebar footer (next to Settings / bug report).\n * Host-rendered for consistent chrome — plugins supply icon, label, and\n * `run` behavior only.\n */\ninterface PluginSidebarFooterActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Tooltip and accessible label for the icon button. */\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /**\n * Runs when the user activates the action (e.g. call `openSettings()`,\n * open a panel via other surfaces, toast). Errors (sync or async) are\n * contained and logged; they never break the sidebar.\n */\n run(context: PluginSidebarFooterActionContext): void | Promise;\n}\n/**\n * Register this plugin as a viewer/editor for file extensions. The user\n * picks (and can set as default) an opener per extension via the file tab's\n * \"Open with\" menu; matching files opened in the panel then render\n * `component` in a plugin tab instead of the built-in preview. Applies to\n * working-tree, host, and thread-storage files — never to git-ref snapshots\n * (diff views always use the built-in preview). The built-in preview stays\n * one menu click away, and a missing/disabled opener falls back to it.\n */\ninterface PluginFileOpenerRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label in the \"Open with\" menu (e.g. \"Notes editor\"). */\n title: string;\n /** Lowercase extensions without the dot (e.g. [\"md\", \"mdx\"]). */\n extensions: readonly string[];\n component: ComponentType;\n}\n/**\n * Register a leaf message directive rendered inside assistant (and nested\n * agent) message Markdown. `id` is the directive name: `inline-vis` matches\n * `::inline-vis{file=\"demo.html\"}`.\n */\ninterface PluginMessageDirectiveRegistration {\n /**\n * The directive name. Lowercase kebab-case beginning with a letter.\n */\n id: string;\n component: ComponentType;\n}\ninterface PluginAppSlots {\n homepageSection(registration: PluginHomepageSectionRegistration): void;\n settingsSection(registration: PluginSettingsSectionRegistration): void;\n navPanel(registration: PluginNavPanelRegistration): void;\n threadPanelAction(registration: PluginThreadPanelActionRegistration): void;\n composerAccessory(registration: PluginComposerAccessoryRegistration): void;\n pendingInteraction(registration: PluginPendingInteractionRegistration): void;\n sidebarFooterAction(registration: PluginSidebarFooterActionRegistration): void;\n fileOpener(registration: PluginFileOpenerRegistration): void;\n messageDirective(registration: PluginMessageDirectiveRegistration): void;\n}\ninterface PluginAppBuilder {\n slots: PluginAppSlots;\n}\ntype PluginAppSetup = (app: PluginAppBuilder) => void;\n/**\n * The opaque product of `definePluginApp` — a plugin's `app.tsx` default\n * export. The host re-runs `setup` against a fresh collector on every\n * (re)interpretation, replacing that plugin's registrations wholesale.\n */\ninterface PluginAppDefinition {\n /** Brand the host checks before interpreting a bundle's default export. */\n readonly __bbPluginApp: true;\n readonly setup: PluginAppSetup;\n}\ninterface PluginRpcClient {\n /**\n * Invoke one of the plugin's `bb.rpc` methods (POST\n * /api/v1/plugins/<id>/rpc/<method>). Resolves with the method's\n * inferred output; rejects with an `Error` carrying the server's message,\n * stable `code`, and validation `issues` when present.\n */\n call>(method: Method, ...args: PluginRpcCallArgs): Promise>;\n}\ninterface PluginSettingsState {\n /**\n * Effective non-secret setting values (secret settings are excluded —\n * read them server-side). Undefined while loading or unavailable.\n */\n values: Record | undefined;\n isLoading: boolean;\n}\n/** State of the app's shared realtime connection to the bb server. */\ntype PluginRealtimeConnectionState = \"connecting\" | \"connected\" | \"reconnecting\";\n/** Where `useComposer()` writes: the active thread's draft or the new-thread draft. */\ntype PluginComposerScope = {\n kind: \"thread\";\n threadId: string;\n} | {\n kind: \"new-thread\";\n projectId: string | null;\n};\n/** An @-mention pill bound to one of the calling plugin's mention providers. */\ninterface PluginComposerMention {\n /** Mention provider id registered by THIS plugin via `bb.ui.registerMentionProvider`. */\n provider: string;\n /** Item id your provider's `resolve` will receive at send time. */\n id: string;\n /** Pill text shown in the composer. */\n label: string;\n}\n/**\n * Programmatic access to the chat composer draft — the same shared draft the\n * built-in \"Add to chat\" affordances (file preview, diff, terminal selections)\n * write to. Inside a thread context writes land in that thread's draft;\n * anywhere else (nav panel, homepage section) they seed the new-thread\n * composer draft, which persists until the user sends or clears it.\n */\ninterface PluginComposerApi {\n scope: PluginComposerScope;\n /** Current plain text for this composer scope. */\n readonly text: string;\n /**\n * Replace the draft's plain text. Attachments are preserved. Inline mentions\n * outside the changed range are preserved and rebased; mentions overlapped\n * by the replacement are removed because their text representation changed.\n */\n setText(next: string): void;\n /**\n * Replace the draft's plain text from the latest committed value. Uses the\n * same structured-state reconciliation as `setText`.\n */\n updateText(updater: (current: string) => string): void;\n /** Clear plain text without clearing independently attached files. */\n clear(): void;\n /**\n * Append text to the draft as a `> ` blockquote block and focus the\n * composer. Blank text is a no-op. This is the \"reference this selection\n * in chat\" primitive.\n */\n addQuote(text: string): void;\n /**\n * Insert an @-mention pill that resolves through this plugin's mention\n * provider at send time — the durable way to reference an entity whose\n * content should be fetched fresh when the message is sent.\n */\n insertMention(mention: PluginComposerMention): void;\n /** Focus the composer caret at the end of the draft. */\n focus(): void;\n}\n/** Current app selection, derived from the route. */\ninterface BbContext {\n projectId: string | null;\n threadId: string | null;\n}\ninterface BbNavigate {\n toThread(threadId: string): void;\n toProject(projectId: string): void;\n /**\n * Navigate to one of this plugin's own nav panels by its `path`.\n * `subPath` targets a location inside the panel (the component's\n * `subPath` prop); `replace` swaps the current history entry instead of\n * pushing — use it for redirects so back does not bounce.\n */\n toPluginPanel(path: string, options?: {\n subPath?: string;\n replace?: boolean;\n }): void;\n /**\n * Navigate to the root compose surface (the new-thread screen). Pass\n * `initialPrompt` to seed the composer draft and `focusPrompt` to focus the\n * composer on arrival — the pairing behind \"Create via chat\" style entry\n * points that drop the user into chat with a prefilled prompt.\n */\n toCompose(options?: {\n initialPrompt?: string;\n focusPrompt?: boolean;\n }): void;\n}\n/**\n * Everything `@bb/plugin-sdk/app` resolves to at runtime. The BB app builds\n * the real implementation and `satisfies` this interface; `bb plugin build`\n * shims the specifier to that object on `globalThis.__bbPluginRuntime`.\n */\ninterface PluginSdkApp {\n definePluginApp(setup: PluginAppSetup): PluginAppDefinition;\n useRpc(): PluginRpcClient;\n useRealtime(channel: string, handler: (payload: unknown) => void): void;\n /**\n * Observe the same shared connection that delivers `useRealtime` signals.\n * Use a subsequent transition to `connected` to reconcile server state that\n * may have changed while ephemeral signals could not be delivered. The first\n * connection can transition from `connecting` and is not a reconnection.\n */\n useRealtimeConnectionState(): PluginRealtimeConnectionState;\n useSettings(): PluginSettingsState;\n useBbContext(): BbContext;\n useBbNavigate(): BbNavigate;\n useComposer(): PluginComposerApi;\n}\n\n/**\n * App-wide server-backed preferences.\n * Client-local settings stay in the frontend localStorage helpers instead.\n */\ndeclare const appSettingsSchema: z$1.ZodObject<{\n caffeinate: z$1.ZodBoolean;\n showKeyboardHints: z$1.ZodBoolean;\n showUnhandledProviderEvents: z$1.ZodBoolean;\n codexMemoryEnabled: z$1.ZodBoolean;\n claudeCodeMemoryEnabled: z$1.ZodBoolean;\n codexSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeWorkflowsDisabled: z$1.ZodBoolean;\n}, z$1.core.$strict>;\ntype AppSettings = z$1.infer;\n\ndeclare const appKeybindingOverridesSchema: z$1.ZodArray;\n shortcut: z$1.ZodNullable>;\n}, z$1.core.$strict>>;\ntype AppKeybindingOverrides = z$1.infer;\n\ndeclare const appThemeSchema: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n}, z$1.core.$strip>;\ntype AppTheme = z$1.infer;\n/**\n * The complete appearance selection a client sends when changing the palette\n * and/or favicon tint. The server validates `themeId` (built-in id or an\n * existing custom theme) and resolves the CSS from disk for custom themes.\n * Callers changing only one facet must carry the other facet forward explicitly.\n */\ndeclare const appThemeSelectionSchema: z$1.ZodObject<{\n themeId: z$1.ZodString;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n}, z$1.core.$strip>;\ntype AppThemeSelection = z$1.infer;\n\ndeclare const changedMessageSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"thread\">;\n id: z$1.ZodOptional;\n metadata: z$1.ZodOptional;\n eventTypes: z$1.ZodOptional>>>>;\n hasPendingInteraction: z$1.ZodOptional;\n projectId: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"project\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"environment\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"host\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"system\">;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>], \"entity\">;\ntype ChangedMessage = z$1.infer;\n\ndeclare const environmentSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodNullable;\n projectId: z$1.ZodString;\n hostId: z$1.ZodString;\n path: z$1.ZodNullable;\n managed: z$1.ZodBoolean;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n branchName: z$1.ZodNullable;\n baseBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n mergeBaseBranch: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n ready: \"ready\";\n retiring: \"retiring\";\n destroying: \"destroying\";\n destroyed: \"destroyed\";\n }>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype Environment = z$1.infer;\n\n/**\n * User-opt-in experiments (the Settings → Experiments toggles). Distinct from\n * `FeatureFlags`: flags are operator-set via env at server start, experiments\n * are user-toggled at runtime and persisted server-side so server-owned\n * policy (e.g. skill injection) can honor them.\n *\n * Every experiment defaults to off — opting in is the point.\n */\ndeclare const experimentsSchema: z$1.ZodObject<{\n claudeCodeMockCliTraffic: z$1.ZodBoolean;\n plugins: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype Experiments = z$1.infer;\n\ndeclare const hostSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n type: z$1.ZodEnum<{\n persistent: \"persistent\";\n }>;\n status: z$1.ZodEnum<{\n connected: \"connected\";\n disconnected: \"disconnected\";\n }>;\n lastSeenAt: z$1.ZodNullable;\n lastRejectedProtocolVersion: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype Host = z$1.infer;\n\ninterface JsonObject {\n [key: string]: JsonValue;\n}\ntype JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;\n\ndeclare const pendingInteractionResolutionSchema: z$1.ZodUnion;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n}, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin_submitted\">;\n}, z$1.core.$strip>]>;\ntype PendingInteractionResolution = z$1.infer;\ndeclare const providerPendingInteractionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n origin: z$1.ZodOptional;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n }, z$1.core.$strip>>;\n payload: z$1.ZodUnion;\n subject: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n itemId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n actions: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"listFiles\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"file_change\">;\n itemId: z$1.ZodString;\n writeScope: z$1.ZodNullable;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>], \"kind\">;\n reason: z$1.ZodNullable;\n availableDecisions: z$1.ZodArray>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>;\n resolution: z$1.ZodNullable;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>>;\n}, z$1.core.$strip>;\ntype ProviderPendingInteraction = z$1.infer;\ndeclare const pluginPendingInteractionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodNullable;\n origin: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n rendererId: z$1.ZodString;\n }, z$1.core.$strip>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n title: z$1.ZodString;\n data: z$1.ZodType>;\n }, z$1.core.$strip>;\n resolution: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginPendingInteraction = z$1.infer;\ntype PendingInteraction = ProviderPendingInteraction | PluginPendingInteraction;\n\ndeclare const projectSourceSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n isDefault: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n type: z$1.ZodLiteral<\"local_path\">;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ProjectSource = z$1.infer;\n\ndeclare const resolvedThreadExecutionOptionsSchema: z$1.ZodObject<{\n seq: z$1.ZodOptional;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n source: z$1.ZodEnum<{\n \"client/thread/start\": \"client/thread/start\";\n \"client/turn/requested\": \"client/turn/requested\";\n \"client/turn/start\": \"client/turn/start\";\n }>;\n}, z$1.core.$strip>;\ntype ResolvedThreadExecutionOptions = z$1.infer;\ndeclare const projectExecutionDefaultsSchema: z$1.ZodObject<{\n providerId: z$1.ZodString;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n}, z$1.core.$strip>;\ntype ProjectExecutionDefaults = z$1.infer;\n\n/** All thread events — provider-originated or system-originated. */\ndeclare const threadEventSchema: z$1.ZodPipe;\n threadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/identity\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/started\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n error: z$1.ZodOptional>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/input/accepted\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n clientRequestId: z$1.ZodString;\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/name/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n threadName: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/compacted\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/goal/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n objective: z$1.ZodString;\n status: z$1.ZodEnum<{\n paused: \"paused\";\n active: \"active\";\n budgetLimited: \"budgetLimited\";\n complete: \"complete\";\n }>;\n tokenBudget: z$1.ZodNullable;\n tokensUsed: z$1.ZodNumber;\n timeUsedSeconds: z$1.ZodNumber;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/goal/cleared\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/started\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"userMessage\">;\n id: z$1.ZodString;\n content: z$1.ZodArray;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n clientRequestId: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"agentMessage\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commandExecution\">;\n id: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n aggregatedOutput: z$1.ZodOptional;\n exitCode: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"fileChange\">;\n id: z$1.ZodString;\n changes: z$1.ZodArray;\n movePath: z$1.ZodOptional;\n diff: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webSearch\">;\n id: z$1.ZodString;\n queries: z$1.ZodArray;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webFetch\">;\n id: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"imageView\">;\n id: z$1.ZodString;\n path: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"toolCall\">;\n id: z$1.ZodString;\n server: z$1.ZodOptional;\n tool: z$1.ZodString;\n arguments: z$1.ZodOptional>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n result: z$1.ZodOptional;\n error: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reasoning\">;\n id: z$1.ZodString;\n summary: z$1.ZodArray;\n content: z$1.ZodArray;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"plan\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"contextCompaction\">;\n id: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"userMessage\">;\n id: z$1.ZodString;\n content: z$1.ZodArray;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n clientRequestId: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"agentMessage\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commandExecution\">;\n id: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n aggregatedOutput: z$1.ZodOptional;\n exitCode: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"fileChange\">;\n id: z$1.ZodString;\n changes: z$1.ZodArray;\n movePath: z$1.ZodOptional;\n diff: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webSearch\">;\n id: z$1.ZodString;\n queries: z$1.ZodArray;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webFetch\">;\n id: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"imageView\">;\n id: z$1.ZodString;\n path: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"toolCall\">;\n id: z$1.ZodString;\n server: z$1.ZodOptional;\n tool: z$1.ZodString;\n arguments: z$1.ZodOptional>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n result: z$1.ZodOptional;\n error: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reasoning\">;\n id: z$1.ZodString;\n summary: z$1.ZodArray;\n content: z$1.ZodArray;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"plan\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"contextCompaction\">;\n id: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/agentMessage/delta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/commandExecution/outputDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n reset: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/fileChange/outputDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/reasoning/summaryTextDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/reasoning/textDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/plan/delta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/mcpToolCall/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n message: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/toolCall/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n message: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/backgroundTask/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/backgroundTask/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n running: \"running\";\n paused: \"paused\";\n completed: \"completed\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/tokenUsage/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n tokenUsage: z$1.ZodObject<{\n total: z$1.ZodObject<{\n totalTokens: z$1.ZodNumber;\n inputTokens: z$1.ZodNumber;\n cachedInputTokens: z$1.ZodNumber;\n outputTokens: z$1.ZodNumber;\n reasoningOutputTokens: z$1.ZodNumber;\n }, z$1.core.$strip>;\n last: z$1.ZodObject<{\n totalTokens: z$1.ZodNumber;\n inputTokens: z$1.ZodNumber;\n cachedInputTokens: z$1.ZodNumber;\n outputTokens: z$1.ZodNumber;\n reasoningOutputTokens: z$1.ZodNumber;\n }, z$1.core.$strip>;\n modelContextWindow: z$1.ZodNullable;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/contextWindowUsage/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n contextWindowUsage: z$1.ZodObject<{\n usedTokens: z$1.ZodNullable;\n modelContextWindow: z$1.ZodNullable;\n estimated: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/plan/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n plan: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n explanation: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/diff/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n diff: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/error\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n message: z$1.ZodString;\n detail: z$1.ZodOptional;\n willRetry: z$1.ZodOptional;\n errorInfo: z$1.ZodOptional;\n providerCode: z$1.ZodNullable;\n httpStatusCode: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/warning\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n category: z$1.ZodEnum<{\n deprecation: \"deprecation\";\n config: \"config\";\n general: \"general\";\n }>;\n summary: z$1.ZodOptional;\n details: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/modelFallback\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n originalModel: z$1.ZodString;\n fallbackModel: z$1.ZodString;\n reason: z$1.ZodEnum<{\n refusal: \"refusal\";\n provider: \"provider\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/unhandled\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerId: z$1.ZodString;\n rawType: z$1.ZodString;\n rawEvent: z$1.ZodObject<{\n jsonrpc: z$1.ZodLiteral<\"2.0\">;\n id: z$1.ZodOptional>;\n method: z$1.ZodString;\n params: z$1.ZodOptional>>;\n }, z$1.core.$strip>;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>], \"type\">, z$1.ZodObject<{\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strip>>, z$1.ZodIntersection;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"client/turn/requested\">;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n requestId: z$1.ZodString;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n senderThreadId: z$1.ZodNullable;\n systemMessageKind: z$1.ZodOptional>;\n systemMessageSubject: z$1.ZodOptional;\n threadId: z$1.ZodString;\n threadName: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-batch\">;\n count: z$1.ZodNumber;\n }, z$1.core.$strip>], \"kind\">>>;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-start\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new-turn\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"auto\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"steer\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>], \"kind\">;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n execution: z$1.ZodObject<{\n seq: z$1.ZodOptional;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n source: z$1.ZodEnum<{\n \"client/thread/start\": \"client/thread/start\";\n \"client/turn/requested\": \"client/turn/requested\";\n \"client/turn/start\": \"client/turn/start\";\n }>;\n permissionMode: z$1.ZodEnum<{\n readonly: \"readonly\";\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n \"workspace-write\": \"workspace-write\";\n }>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"client/turn/start\">;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/error\">;\n threadId: z$1.ZodString;\n code: z$1.ZodOptional;\n message: z$1.ZodString;\n detail: z$1.ZodOptional;\n reconnectAttempt: z$1.ZodOptional;\n reconnectTotal: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/manager/user_message\">;\n threadId: z$1.ZodString;\n text: z$1.ZodString;\n toolCallId: z$1.ZodOptional;\n turnId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/thread/interrupted\">;\n threadId: z$1.ZodString;\n reason: z$1.ZodEnum<{\n \"manual-stop\": \"manual-stop\";\n \"host-daemon-restarted\": \"host-daemon-restarted\";\n \"provider-turn-idle\": \"provider-turn-idle\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/operation\">;\n threadId: z$1.ZodString;\n operation: z$1.ZodString;\n status: z$1.ZodString;\n message: z$1.ZodString;\n operationId: z$1.ZodString;\n metadata: z$1.ZodOptional>>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/permissionGrant/lifecycle\">;\n threadId: z$1.ZodString;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n resolution: z$1.ZodDefault;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">>>;\n statusReason: z$1.ZodDefault>;\n subject: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/userQuestion/lifecycle\">;\n threadId: z$1.ZodString;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n resolution: z$1.ZodDefault;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>>;\n statusReason: z$1.ZodDefault>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/thread-provisioning\">;\n threadId: z$1.ZodString;\n provisioningId: z$1.ZodString;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n active: \"active\";\n cancelled: \"cancelled\";\n }>;\n environmentId: z$1.ZodString;\n entries: z$1.ZodArray;\n key: z$1.ZodString;\n text: z$1.ZodString;\n startedAt: z$1.ZodOptional;\n status: z$1.ZodOptional>;\n metadata: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/provider-turn-watchdog\">;\n threadId: z$1.ZodString;\n reason: z$1.ZodLiteral<\"provider-turn-idle\">;\n thresholdMs: z$1.ZodNumber;\n elapsedMs: z$1.ZodNumber;\n activeTurnId: z$1.ZodString;\n activeTurnStartedAt: z$1.ZodNumber;\n lastActivityEventSequence: z$1.ZodNumber;\n lastActivityEventType: z$1.ZodString;\n lastActivityEventAt: z$1.ZodNumber;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodNullable;\n firedAt: z$1.ZodNumber;\n}, z$1.core.$strip>]>, z$1.ZodObject<{\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strip>>]>>;\ntype ThreadEvent = z$1.infer;\ntype ThreadEventType = ThreadEvent[\"type\"];\n\ndeclare const providerInfoSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n displayName: z$1.ZodString;\n logoUrl: z$1.ZodNullable;\n capabilities: z$1.ZodObject<{\n supportsArchive: z$1.ZodBoolean;\n supportsRename: z$1.ZodBoolean;\n supportsServiceTier: z$1.ZodBoolean;\n supportsUserQuestion: z$1.ZodBoolean;\n supportsFork: z$1.ZodBoolean;\n supportedPermissionModes: z$1.ZodArray>;\n }, z$1.core.$strip>;\n composerActions: z$1.ZodArray;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plan\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"goal\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>], \"kind\">>;\n available: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype ProviderInfo = z$1.infer;\n\ndeclare const threadEventScopeSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n}, z$1.core.$strip>], \"kind\">;\ntype ThreadEventScope = z$1.infer;\n\ntype ThreadEventByType = {\n [TType in ThreadEventType]: Extract;\n};\ntype ThreadEventForType = ThreadEventByType[TType];\ntype StoredThreadEventDataFromEvent = Omit;\ninterface ThreadEventRowBase {\n id: string;\n scope: ThreadEventScope;\n threadId: string;\n seq: number;\n createdAt: number;\n actorHandle: string | null;\n}\ntype ThreadEventRowFromEvent = ThreadEventRowBase & {\n type: TEvent[\"type\"];\n data: StoredThreadEventDataFromEvent;\n};\ntype ThreadEventRowOfType = ThreadEventRowFromEvent>;\ntype ThreadEventRow = {\n [TType in ThreadEventType]: ThreadEventRowOfType;\n}[ThreadEventType];\n\ndeclare const threadStatusSchema: z$1.ZodEnum<{\n error: \"error\";\n active: \"active\";\n starting: \"starting\";\n idle: \"idle\";\n stopping: \"stopping\";\n}>;\ntype ThreadStatus = z$1.infer;\n\ndeclare const threadTimelinePendingTodosSchema: z$1.ZodObject<{\n sourceSeq: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n items: z$1.ZodArray;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ThreadTimelinePendingTodos = z$1.infer;\n\ndeclare const threadQueuedMessageSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n content: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadQueuedMessage = z$1.infer;\n\ndeclare const workspaceFileListResponseSchema: z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype WorkspaceFileListResponse = z$1.infer;\ndeclare const workspacePathListResponseSchema: z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype WorkspacePathListResponse = z$1.infer;\n\ndeclare const createProjectSourceRequestSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodPipe>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"clone\">;\n targetPath: z$1.ZodOptional>>;\n remoteUrl: z$1.ZodOptional;\n}, z$1.core.$strict>], \"type\">;\ntype CreateProjectSourceRequest = z$1.infer;\ndeclare const createProjectRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n source: z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodPipe>;\n }, z$1.core.$strict>;\n}, z$1.core.$strip>;\ntype CreateProjectRequest = z$1.infer;\ndeclare const threadSectionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadSectionResponse = z$1.infer;\ndeclare const createThreadSectionRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype CreateThreadSectionRequest = z$1.infer;\ndeclare const updateThreadSectionRequestSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateThreadSectionRequest = z$1.infer;\ndeclare const deleteThreadSectionRequestSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n}, z$1.core.$strict>;\ntype DeleteThreadSectionRequest = z$1.infer;\ndeclare const threadSectionMutationResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n updatedThreadCount: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadSectionMutationResponse = z$1.infer;\ndeclare const reorderProjectRequestSchema: z$1.ZodObject<{\n previousProjectId: z$1.ZodNullable;\n nextProjectId: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ReorderProjectRequest = z$1.infer;\ndeclare const projectListQuerySchema: z$1.ZodObject<{\n include: z$1.ZodOptional;\n includePersonal: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype ProjectListQuery = z$1.infer;\ndeclare const projectFilesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional>;\n limit: z$1.ZodOptional>;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectFilesQuery = z$1.infer;\ndeclare const projectPathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional>;\n limit: z$1.ZodOptional>;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectPathsQuery = z$1.infer;\ndeclare const projectFileContentQuerySchema: z$1.ZodObject<{\n path: z$1.ZodString;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectFileContentQuery = z$1.infer;\ndeclare const projectBranchesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n hostId: z$1.ZodString;\n selectedBranch: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ProjectBranchesQuery = z$1.infer;\ndeclare const projectBranchesResponseSchema: z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n defaultBranch: z$1.ZodNullable;\n defaultBranchRelation: z$1.ZodNullable>;\n hasUncommittedChanges: z$1.ZodBoolean;\n operation: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"none\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"rebase\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"cherry-pick\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"revert\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>], \"kind\">;\n originDefaultBranch: z$1.ZodNullable;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n defaultWorktreeBaseBranch: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ProjectBranchesResponse = z$1.infer;\ndeclare const promptHistoryQuerySchema: z$1.ZodObject<{\n limit: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PromptHistoryQuery = z$1.infer;\ndeclare const promptHistoryResponseSchema: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>>;\ntype PromptHistoryResponse = z$1.infer;\ndeclare const updateProjectRequestSchema: z$1.ZodObject<{\n name: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype UpdateProjectRequest = z$1.infer;\ndeclare const updateProjectSourceRequestSchema: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodOptional>>;\n isDefault: z$1.ZodOptional>;\n}, z$1.core.$strict>;\ntype UpdateProjectSourceRequest = z$1.infer;\ndeclare const commandListResponseSchema: z$1.ZodObject<{\n commands: z$1.ZodArray;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n description: z$1.ZodNullable;\n argumentHint: z$1.ZodNullable;\n pluginId: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype CommandListResponse = z$1.infer;\n/** Query for the complete command catalog available to a project and provider. */\ndeclare const projectCommandsQuerySchema: z$1.ZodObject<{\n provider: z$1.ZodString;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strict>;\ntype ProjectCommandsQuery = z$1.infer;\ndeclare const projectResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodEnum<{\n personal: \"personal\";\n standard: \"standard\";\n }>;\n name: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n sources: z$1.ZodArray;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ProjectResponse = z$1.infer;\ndeclare const projectWithThreadsResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodEnum<{\n personal: \"personal\";\n standard: \"standard\";\n }>;\n name: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n sources: z$1.ZodArray;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n threads: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>>;\n defaultExecutionOptions: z$1.ZodNullable;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ProjectWithThreadsResponse = z$1.infer;\ndeclare const uploadedPromptAttachmentSchema: z$1.ZodObject<{\n type: z$1.ZodEnum<{\n localImage: \"localImage\";\n localFile: \"localFile\";\n }>;\n path: z$1.ZodString;\n name: z$1.ZodString;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype UploadedPromptAttachment = z$1.infer;\ndeclare const copyProjectAttachmentsRequestSchema: z$1.ZodObject<{\n sourceProjectId: z$1.ZodString;\n paths: z$1.ZodArray;\n}, z$1.core.$strict>;\ntype CopyProjectAttachmentsRequest = z$1.infer;\n\ndeclare const updateEnvironmentRequestSchema: z$1.ZodObject<{\n mergeBaseBranch: z$1.ZodOptional>;\n name: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype UpdateEnvironmentRequest = z$1.infer;\n/**\n * Query for searching paths in an environment's workspace. Unlike the\n * project-scoped variant this needs no `environmentId` — the environment is\n * the route param — and is project-agnostic, so it works for projectless\n * (personal) environments too.\n */\ndeclare const environmentPathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n}, z$1.core.$strip>;\ntype EnvironmentPathsQuery = z$1.infer;\ndeclare const environmentDiffBranchesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n selectedBranch: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype EnvironmentDiffBranchesQuery = z$1.infer;\ndeclare const environmentDiffBranchesResponseSchema: z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype EnvironmentDiffBranchesResponse = z$1.infer;\ndeclare const environmentStatusQuerySchema: z$1.ZodObject<{\n mergeBaseBranch: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype EnvironmentStatusQuery = z$1.infer;\ndeclare const environmentDiffQuerySchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n target: z$1.ZodLiteral<\"uncommitted\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodPipe;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodPipe;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n}, z$1.core.$strip>], \"target\">;\ntype EnvironmentDiffQuery = z$1.infer;\n/**\n * Query for fetching a single file's contents at one side of a diff target.\n * Used by the diff card to reparse the card's patch with full old/new contents\n * so `@pierre/diffs` can render expand-context buttons between hunks.\n *\n * For `branch_committed` / `all`, callers pass the resolved merge-base SHA\n * (`mergeBaseRef`, surfaced by `workspace.diff`) rather than the branch name\n * — the diff itself was computed against that SHA, so reading the old side\n * from the same SHA keeps the file content aligned with the hunk line\n * numbers. Reading from the branch tip is wrong whenever the branch has\n * moved past the merge-base since the file existed there.\n */\ndeclare const environmentDiffFileQuerySchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n target: z$1.ZodLiteral<\"uncommitted\">;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseRef: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"all\">;\n mergeBaseRef: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>], \"target\">;\ntype EnvironmentDiffFileQuery = z$1.infer;\ndeclare const environmentDiffFileResponseSchema: z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n utf8: \"utf8\";\n base64: \"base64\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype EnvironmentDiffFileResponse = z$1.infer;\ndeclare const environmentArchiveThreadsResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n archivedThreadIds: z$1.ZodArray;\n}, z$1.core.$strip>;\ntype EnvironmentArchiveThreadsResponse = z$1.infer;\ndeclare const pullRequestMergeMethodSchema: z$1.ZodEnum<{\n merge: \"merge\";\n squash: \"squash\";\n rebase: \"rebase\";\n}>;\ntype PullRequestMergeMethod = z$1.infer;\ndeclare const commitActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"commit\">;\n message: z$1.ZodString;\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n}, z$1.core.$strip>;\ntype CommitActionResponse = z$1.infer;\ndeclare const squashMergeActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"squash_merge\">;\n merged: z$1.ZodBoolean;\n message: z$1.ZodString;\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SquashMergeActionResponse = z$1.infer;\ndeclare const pullRequestReadyActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_ready\">;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestReadyActionResponse = z$1.infer;\ndeclare const pullRequestMergeActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_merge\">;\n method: z$1.ZodEnum<{\n merge: \"merge\";\n squash: \"squash\";\n rebase: \"rebase\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestMergeActionResponse = z$1.infer;\ndeclare const pullRequestDraftActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_draft\">;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestDraftActionResponse = z$1.infer;\ndeclare const environmentStatusResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n workspace: z$1.ZodObject<{\n workingTree: z$1.ZodObject<{\n insertions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n files: z$1.ZodArray;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n hasUncommittedChanges: z$1.ZodBoolean;\n state: z$1.ZodEnum<{\n clean: \"clean\";\n untracked: \"untracked\";\n dirty_uncommitted: \"dirty_uncommitted\";\n committed_unmerged: \"committed_unmerged\";\n dirty_and_committed_unmerged: \"dirty_and_committed_unmerged\";\n }>;\n }, z$1.core.$strip>;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n branch: z$1.ZodObject<{\n currentBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodString;\n }, z$1.core.$strip>;\n mergeBase: z$1.ZodNullable;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n mergeBaseBranch: z$1.ZodString;\n baseRef: z$1.ZodNullable;\n aheadCount: z$1.ZodNumber;\n behindCount: z$1.ZodNumber;\n hasCommittedUnmergedChanges: z$1.ZodBoolean;\n commits: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\n/**\n * Structured pull-request lookup outcome. \"absent\" is a real answer — the\n * host checked and the branch has no PR (non-git environments resolve to\n * \"absent\" without a daemon call). \"unavailable\" means the lookup itself\n * failed (gh missing, not authenticated, timeout, unreachable workspace), so\n * callers must not render it as \"no PR exists\".\n */\ndeclare const environmentPullRequestResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n pullRequest: z$1.ZodObject<{\n number: z$1.ZodNumber;\n title: z$1.ZodString;\n state: z$1.ZodEnum<{\n merged: \"merged\";\n draft: \"draft\";\n open: \"open\";\n closed: \"closed\";\n }>;\n url: z$1.ZodString;\n baseRefName: z$1.ZodString;\n headRefName: z$1.ZodString;\n updatedAt: z$1.ZodString;\n checks: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n unknown: \"unknown\";\n pending: \"pending\";\n passing: \"passing\";\n failing: \"failing\";\n no_checks: \"no_checks\";\n }>;\n totalCount: z$1.ZodNumber;\n passedCount: z$1.ZodNumber;\n failedCount: z$1.ZodNumber;\n pendingCount: z$1.ZodNumber;\n }, z$1.core.$strict>;\n review: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n none: \"none\";\n approved: \"approved\";\n changes_requested: \"changes_requested\";\n review_required: \"review_required\";\n review_requested: \"review_requested\";\n }>;\n reviewRequestCount: z$1.ZodNumber;\n }, z$1.core.$strict>;\n mergeability: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n unknown: \"unknown\";\n blocked: \"blocked\";\n draft: \"draft\";\n mergeable: \"mergeable\";\n conflicts: \"conflicts\";\n }>;\n mergeStateStatus: z$1.ZodNullable>;\n mergeable: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n attention: z$1.ZodEnum<{\n none: \"none\";\n blocked: \"blocked\";\n merged: \"merged\";\n draft: \"draft\";\n closed: \"closed\";\n changes_requested: \"changes_requested\";\n review_requested: \"review_requested\";\n conflicts: \"conflicts\";\n checks_failed: \"checks_failed\";\n checks_pending: \"checks_pending\";\n ready_to_merge: \"ready_to_merge\";\n }>;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"absent\">;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n message: z$1.ZodString;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentPullRequestResponse = z$1.infer;\ndeclare const environmentDiffResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n diff: z$1.ZodObject<{\n diff: z$1.ZodString;\n truncated: z$1.ZodBoolean;\n shortstat: z$1.ZodString;\n files: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strip>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffResponse = z$1.infer;\ndeclare const environmentDiffFilesResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n files: z$1.ZodArray;\n changeKind: z$1.ZodEnum<{\n deleted: \"deleted\";\n added: \"added\";\n modified: \"modified\";\n renamed: \"renamed\";\n copied: \"copied\";\n type_changed: \"type_changed\";\n }>;\n additions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n binary: z$1.ZodBoolean;\n origin: z$1.ZodEnum<{\n untracked: \"untracked\";\n tracked: \"tracked\";\n }>;\n loadMode: z$1.ZodEnum<{\n auto: \"auto\";\n on_demand: \"on_demand\";\n too_large: \"too_large\";\n }>;\n }, z$1.core.$strip>>;\n shortstat: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n initialPatches: z$1.ZodArray>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n too_many_files: \"too_many_files\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffFilesResponse = z$1.infer;\ndeclare const environmentDiffPatchResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n patches: z$1.ZodArray>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffPatchResponse = z$1.infer;\n/**\n * Body for `POST /diff/patch`: the diff target plus the list of new paths whose\n * patches the client wants. A POST (not GET) because the repeated `paths` array\n * cannot survive flat query parsing. The client supplies only new paths; the\n * server re-derives each file's rename/copy pairing (`previousPath`) from its\n * own TOC.\n */\ndeclare const environmentDiffPatchRequestSchema: z$1.ZodObject<{\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n paths: z$1.ZodArray;\n}, z$1.core.$strict>;\ntype EnvironmentDiffPatchRequest = z$1.infer;\ntype EnvironmentStatusResponse = z$1.infer;\n\ndeclare const providerUsageResponseSchema: z$1.ZodObject<{\n codex: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n claudeCode: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n cursor: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n}, z$1.core.$strip>;\ntype ProviderUsageResponse = z$1.infer;\ntype HostDaemonCommandTransport = \"settled\" | \"onlineRpc\";\ntype HostDaemonCommandEnvironmentLane = \"read\" | \"write\";\ntype HostDaemonFlushEventsBeforeResult = boolean | \"when-initiated\";\ninterface HostDaemonCommandDescriptor {\n type: Type;\n schema: Schema;\n resultSchema: ResultSchema;\n transport: Transport;\n retryable: Retryable;\n flushEventsBeforeResult: HostDaemonFlushEventsBeforeResult;\n envLane: HostDaemonCommandEnvironmentLane | null;\n}\ndeclare const hostDaemonCommandRegistry: {\n \"thread.start\": HostDaemonCommandDescriptor<\"thread.start\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n projectId: z$1.ZodString;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n options: z$1.ZodIntersection;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n claudeCodePermissionMode: z$1.ZodOptional>;\n claudeCodeMockCliTraffic: z$1.ZodOptional>;\n workflowsEnabled: z$1.ZodBoolean;\n memoryEnabled: z$1.ZodOptional;\n providerSubagentsEnabled: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"accept-edits\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"user\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"auto\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"automatic\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"full\">;\n permissionScope: z$1.ZodLiteral<\"full\">;\n approvalReviewer: z$1.ZodNull;\n permissionEscalation: z$1.ZodNull;\n }, z$1.core.$strip>], \"permissionMode\">>;\n instructions: z$1.ZodString;\n dynamicTools: z$1.ZodArray>;\n injectedSkillSources: z$1.ZodArray;\n treeHash: z$1.ZodString;\n entryPath: z$1.ZodString;\n sourceType: z$1.ZodEnum<{\n builtin: \"builtin\";\n \"data-dir\": \"data-dir\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n name: z$1.ZodString;\n description: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-path\">;\n sourceType: z$1.ZodLiteral<\"project\">;\n sourceRootPath: z$1.ZodString;\n skillFilePath: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n disallowedTools: z$1.ZodOptional>;\n instructionMode: z$1.ZodEnum<{\n replace: \"replace\";\n append: \"append\";\n }>;\n type: z$1.ZodLiteral<\"thread.start\">;\n requestId: z$1.ZodString;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n speaker: z$1.ZodOptional>;\n threadStoragePath: z$1.ZodOptional;\n fork: z$1.ZodOptional>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"turn.submit\": HostDaemonCommandDescriptor<\"turn.submit\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"turn.submit\">;\n requestId: z$1.ZodString;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n speaker: z$1.ZodOptional>;\n options: z$1.ZodIntersection;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n claudeCodePermissionMode: z$1.ZodOptional>;\n claudeCodeMockCliTraffic: z$1.ZodOptional>;\n workflowsEnabled: z$1.ZodBoolean;\n memoryEnabled: z$1.ZodOptional;\n providerSubagentsEnabled: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"accept-edits\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"user\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"auto\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"automatic\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"full\">;\n permissionScope: z$1.ZodLiteral<\"full\">;\n approvalReviewer: z$1.ZodNull;\n permissionEscalation: z$1.ZodNull;\n }, z$1.core.$strip>], \"permissionMode\">>;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n resumeContext: z$1.ZodObject<{\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n instructionMode: z$1.ZodEnum<{\n replace: \"replace\";\n append: \"append\";\n }>;\n projectId: z$1.ZodString;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n instructions: z$1.ZodString;\n dynamicTools: z$1.ZodArray>;\n injectedSkillSources: z$1.ZodArray;\n treeHash: z$1.ZodString;\n entryPath: z$1.ZodString;\n sourceType: z$1.ZodEnum<{\n builtin: \"builtin\";\n \"data-dir\": \"data-dir\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n name: z$1.ZodString;\n description: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-path\">;\n sourceType: z$1.ZodLiteral<\"project\">;\n sourceRootPath: z$1.ZodString;\n skillFilePath: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n disallowedTools: z$1.ZodOptional>;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"start\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"auto\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"steer\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>], \"mode\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n appliedAs: z$1.ZodEnum<{\n steer: \"steer\";\n \"new-turn\": \"new-turn\";\n }>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"thread.stop\": HostDaemonCommandDescriptor<\"thread.stop\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.stop\">;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.rename\": HostDaemonCommandDescriptor<\"thread.rename\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.rename\">;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.archive\": HostDaemonCommandDescriptor<\"thread.archive\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"thread.archive\">;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.unarchive\": HostDaemonCommandDescriptor<\"thread.unarchive\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.unarchive\">;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"interactive.resolve\": HostDaemonCommandDescriptor<\"interactive.resolve\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"interactive.resolve\">;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n resolution: z$1.ZodUnion;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin_submitted\">;\n }, z$1.core.$strip>]>;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"codex.inference.complete\": HostDaemonCommandDescriptor<\"codex.inference.complete\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"codex.inference.complete\">;\n model: z$1.ZodString;\n prompt: z$1.ZodString;\n outputSchema: z$1.ZodType>;\n timeoutMs: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n model: z$1.ZodString;\n value: z$1.ZodType>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"codex.voice.transcribe\": HostDaemonCommandDescriptor<\"codex.voice.transcribe\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"codex.voice.transcribe\">;\n model: z$1.ZodString;\n audioBase64: z$1.ZodString;\n mimeType: z$1.ZodString;\n filename: z$1.ZodString;\n prompt: z$1.ZodNullable;\n timeoutMs: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n model: z$1.ZodString;\n text: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"environment.provision\": HostDaemonCommandDescriptor<\"environment.provision\", z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n workspaceProvisionType: z$1.ZodLiteral<\"unmanaged\">;\n path: z$1.ZodString;\n checkout: z$1.ZodOptional;\n name: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new\">;\n name: z$1.ZodString;\n baseBranch: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n sourcePath: z$1.ZodString;\n targetPath: z$1.ZodString;\n branchName: z$1.ZodString;\n baseBranch: z$1.ZodNullable;\n setupTimeoutMs: z$1.ZodNumber;\n workspaceProvisionType: z$1.ZodLiteral<\"managed-worktree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n workspaceProvisionType: z$1.ZodLiteral<\"personal\">;\n targetPath: z$1.ZodString;\n }, z$1.core.$strict>], \"workspaceProvisionType\">, z$1.ZodObject<{\n path: z$1.ZodString;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n branchName: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n transcript: z$1.ZodArray;\n key: z$1.ZodString;\n text: z$1.ZodString;\n startedAt: z$1.ZodOptional;\n status: z$1.ZodOptional>;\n metadata: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"project.clone\": HostDaemonCommandDescriptor<\"project.clone\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.clone\">;\n remoteUrl: z$1.ZodString;\n projectSlug: z$1.ZodString;\n targetPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n }, z$1.core.$strict>, \"settled\", false>;\n \"environment.provision.cancel\": HostDaemonCommandDescriptor<\"environment.provision.cancel\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision.cancel\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n aborted: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"settled\", false>;\n \"environment.destroy\": HostDaemonCommandDescriptor<\"environment.destroy\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"environment.destroy\">;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"workspace.commit\": HostDaemonCommandDescriptor<\"workspace.commit\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.commit\">;\n message: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"workspace.squash_merge\": HostDaemonCommandDescriptor<\"workspace.squash_merge\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.squash_merge\">;\n targetBranch: z$1.ZodString;\n commitMessage: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n merged: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"settled\", false>;\n \"workspace.pull_request_action\": HostDaemonCommandDescriptor<\"workspace.pull_request_action\", z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"ready\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"draft\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"merge\">;\n method: z$1.ZodEnum<{\n merge: \"merge\";\n squash: \"squash\";\n rebase: \"rebase\";\n }>;\n }, z$1.core.$strict>], \"operation\">, z$1.ZodObject<{}, z$1.core.$strict>, \"settled\", false>;\n \"host.list_files\": HostDaemonCommandDescriptor<\"host.list_files\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_files\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n }, z$1.core.$strip>, z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.list_paths\": HostDaemonCommandDescriptor<\"host.list_paths\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_paths\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n includeFiles: z$1.ZodBoolean;\n includeDirectories: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.mkdir\": HostDaemonCommandDescriptor<\"host.mkdir\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.mkdir\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n recursive: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.move_path\": HostDaemonCommandDescriptor<\"host.move_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.move_path\">;\n sourcePath: z$1.ZodString;\n destinationPath: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.remove_path\": HostDaemonCommandDescriptor<\"host.remove_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.remove_path\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n recursive: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.browse_directory\": HostDaemonCommandDescriptor<\"host.browse_directory\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.browse_directory\">;\n path: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n directory: z$1.ZodString;\n parent: z$1.ZodNullable;\n entries: z$1.ZodArray;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.paths_exist\": HostDaemonCommandDescriptor<\"host.paths_exist\", z$1.ZodObject<{\n paths: z$1.ZodPipe, z$1.ZodTransform>;\n type: z$1.ZodLiteral<\"host.paths_exist\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n existence: z$1.ZodRecord;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"project.inspect\": HostDaemonCommandDescriptor<\"project.inspect\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.inspect\">;\n path: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"project.clone_default_path\": HostDaemonCommandDescriptor<\"project.clone_default_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.clone_default_path\">;\n projectSlug: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"host.pick_folder\": HostDaemonCommandDescriptor<\"host.pick_folder\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.pick_folder\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, \"onlineRpc\", false>;\n \"host.caffeinate\": HostDaemonCommandDescriptor<\"host.caffeinate\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.caffeinate\">;\n enabled: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n enabled: z$1.ZodBoolean;\n supported: z$1.ZodBoolean;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"connect-tunnel.ensure-identity\": HostDaemonCommandDescriptor<\"connect-tunnel.ensure-identity\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"connect-tunnel.ensure-identity\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n label: z$1.ZodString;\n baseDomain: z$1.ZodString;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"host.list_commands\": HostDaemonCommandDescriptor<\"host.list_commands\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_commands\">;\n providerId: z$1.ZodString;\n cwd: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commands: z$1.ZodArray;\n origin: z$1.ZodEnum<{\n project: \"project\";\n user: \"user\";\n }>;\n description: z$1.ZodNullable;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.list_branches\": HostDaemonCommandDescriptor<\"host.list_branches\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_branches\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n selectedBranch: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n }, z$1.core.$strip>, z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n defaultBranch: z$1.ZodNullable;\n defaultBranchRelation: z$1.ZodNullable>;\n hasUncommittedChanges: z$1.ZodBoolean;\n operation: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"none\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"rebase\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"cherry-pick\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"revert\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>], \"kind\">;\n originDefaultBranch: z$1.ZodNullable;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.file_metadata\": HostDaemonCommandDescriptor<\"host.file_metadata\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.file_metadata\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n modifiedAtMs: z$1.ZodNumber;\n sizeBytes: z$1.ZodNumber;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.read_file\": HostDaemonCommandDescriptor<\"host.read_file\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.read_file\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n ref: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n modifiedAtMs: z$1.ZodOptional;\n sha256: z$1.ZodString;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.read_file_relative\": HostDaemonCommandDescriptor<\"host.read_file_relative\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.read_file_relative\">;\n rootPath: z$1.ZodString;\n path: z$1.ZodString;\n dotfiles: z$1.ZodEnum<{\n deny: \"deny\";\n allow: \"allow\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n modifiedAtMs: z$1.ZodOptional;\n sha256: z$1.ZodString;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.write_file\": HostDaemonCommandDescriptor<\"host.write_file\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.write_file\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n createParents: z$1.ZodBoolean;\n expectedSha256: z$1.ZodOptional>;\n mode: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"written\">;\n sha256: z$1.ZodString;\n sizeBytes: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"conflict\">;\n currentSha256: z$1.ZodNullable;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", false>;\n \"provider.list_models\": HostDaemonCommandDescriptor<\"provider.list_models\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider.list_models\">;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n models: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n selectedOnlyModels: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"known_acp_agents.status\": HostDaemonCommandDescriptor<\"known_acp_agents.status\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"known_acp_agents.status\">;\n agents: z$1.ZodArray>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n agents: z$1.ZodArray;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"provider.usage\": HostDaemonCommandDescriptor<\"provider.usage\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider.usage\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n codex: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n claudeCode: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n cursor: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"provider_cli.status\": HostDaemonCommandDescriptor<\"provider_cli.status\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider_cli.status\">;\n }, z$1.core.$strict>, z$1.ZodRecord, z$1.ZodObject<{\n displayName: z$1.ZodString;\n executableName: z$1.ZodString;\n executablePath: z$1.ZodNullable;\n installed: z$1.ZodBoolean;\n installSource: z$1.ZodEnum<{\n notInstalled: \"notInstalled\";\n npmGlobal: \"npmGlobal\";\n external: \"external\";\n }>;\n currentVersion: z$1.ZodNullable;\n latestVersion: z$1.ZodNullable;\n minimumSupportedVersion: z$1.ZodNullable;\n npmPackageName: z$1.ZodNullable;\n npmGlobalPackageVersion: z$1.ZodNullable;\n installAction: z$1.ZodNullable;\n label: z$1.ZodEnum<{\n Install: \"Install\";\n Update: \"Update\";\n }>;\n commandKind: z$1.ZodEnum<{\n exec: \"exec\";\n shell: \"shell\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>>;\n needsUpdate: z$1.ZodBoolean;\n versionUnsupported: z$1.ZodBoolean;\n }, z$1.core.$strip>>, \"onlineRpc\", true>;\n \"provider_cli.install\": HostDaemonCommandDescriptor<\"provider_cli.install\", z$1.ZodObject<{\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n actionKind: z$1.ZodEnum<{\n install: \"install\";\n update: \"update\";\n }>;\n type: z$1.ZodLiteral<\"provider_cli.install\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n events: z$1.ZodArray;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"output\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n stream: z$1.ZodEnum<{\n stdout: \"stdout\";\n stderr: \"stderr\";\n }>;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"completed\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n exitCode: z$1.ZodNullable;\n signal: z$1.ZodNullable;\n success: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"error\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"workspace.status\": HostDaemonCommandDescriptor<\"workspace.status\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.status\">;\n mergeBaseBranch: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n workspaceStatus: z$1.ZodObject<{\n workingTree: z$1.ZodObject<{\n insertions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n files: z$1.ZodArray;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n hasUncommittedChanges: z$1.ZodBoolean;\n state: z$1.ZodEnum<{\n clean: \"clean\";\n untracked: \"untracked\";\n dirty_uncommitted: \"dirty_uncommitted\";\n committed_unmerged: \"committed_unmerged\";\n dirty_and_committed_unmerged: \"dirty_and_committed_unmerged\";\n }>;\n }, z$1.core.$strip>;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n branch: z$1.ZodObject<{\n currentBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodString;\n }, z$1.core.$strip>;\n mergeBase: z$1.ZodNullable;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n mergeBaseBranch: z$1.ZodString;\n baseRef: z$1.ZodNullable;\n aheadCount: z$1.ZodNumber;\n behindCount: z$1.ZodNumber;\n hasCommittedUnmergedChanges: z$1.ZodBoolean;\n commits: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diff\": HostDaemonCommandDescriptor<\"workspace.diff\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diff\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n maxDiffBytes: z$1.ZodNumber;\n maxFileListBytes: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n diff: z$1.ZodObject<{\n diff: z$1.ZodString;\n truncated: z$1.ZodBoolean;\n shortstat: z$1.ZodString;\n files: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strip>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diffFiles\": HostDaemonCommandDescriptor<\"workspace.diffFiles\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diffFiles\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n files: z$1.ZodArray;\n statusLetter: z$1.ZodEnum<{\n M: \"M\";\n A: \"A\";\n D: \"D\";\n R: \"R\";\n C: \"C\";\n T: \"T\";\n }>;\n additions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n binary: z$1.ZodBoolean;\n origin: z$1.ZodEnum<{\n untracked: \"untracked\";\n tracked: \"tracked\";\n }>;\n }, z$1.core.$strip>>;\n shortstat: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diffPatch\": HostDaemonCommandDescriptor<\"workspace.diffPatch\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diffPatch\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n paths: z$1.ZodArray;\n maxBytesPerFile: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n patches: z$1.ZodArray>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.pull_request\": HostDaemonCommandDescriptor<\"workspace.pull_request\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request\">;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n pullRequest: z$1.ZodObject<{\n number: z$1.ZodNumber;\n title: z$1.ZodString;\n state: z$1.ZodEnum<{\n OPEN: \"OPEN\";\n CLOSED: \"CLOSED\";\n MERGED: \"MERGED\";\n }>;\n url: z$1.ZodString;\n isDraft: z$1.ZodBoolean;\n baseRefName: z$1.ZodString;\n headRefName: z$1.ZodString;\n updatedAt: z$1.ZodString;\n checks: z$1.ZodArray;\n conclusion: z$1.ZodNullable>;\n url: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n reviewDecision: z$1.ZodNullable>;\n reviewRequestCount: z$1.ZodNumber;\n mergeStateStatus: z$1.ZodNullable>;\n mergeable: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"absent\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n message: z$1.ZodString;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n};\ntype HostDaemonCommandRegistry = typeof hostDaemonCommandRegistry;\ntype AnyHostDaemonCommandDescriptor = HostDaemonCommandRegistry[keyof HostDaemonCommandRegistry];\ntype HostDaemonCommandDescriptorForTransport = Extract;\ntype HostDaemonResultSchemaMapForTransport = {\n [Descriptor in HostDaemonCommandDescriptorForTransport as Descriptor[\"type\"]]: Descriptor[\"resultSchema\"];\n};\ntype HostDaemonOnlineRpcResultSchemaMap = HostDaemonResultSchemaMapForTransport<\"onlineRpc\">;\ntype HostDaemonOnlineRpcResultByType = {\n [K in keyof HostDaemonOnlineRpcResultSchemaMap]: z$1.infer;\n};\n\ndeclare const pickFolderResponseSchema: z$1.ZodObject<{\n path: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype PickFolderResponse = z$1.infer;\ndeclare const pathsExistRequestSchema: z$1.ZodObject<{\n paths: z$1.ZodPipe, z$1.ZodTransform>;\n}, z$1.core.$strip>;\ntype PathsExistRequest = z$1.infer;\ndeclare const pathsExistResponseSchema: z$1.ZodObject<{\n existence: z$1.ZodRecord;\n}, z$1.core.$strip>;\ntype PathsExistResponse = z$1.infer;\ndeclare const providerCliStatusResponseSchema: z$1.ZodRecord, z$1.ZodObject<{\n displayName: z$1.ZodString;\n executableName: z$1.ZodString;\n executablePath: z$1.ZodNullable;\n installed: z$1.ZodBoolean;\n installSource: z$1.ZodEnum<{\n notInstalled: \"notInstalled\";\n npmGlobal: \"npmGlobal\";\n external: \"external\";\n }>;\n currentVersion: z$1.ZodNullable;\n latestVersion: z$1.ZodNullable;\n minimumSupportedVersion: z$1.ZodNullable;\n npmPackageName: z$1.ZodNullable;\n npmGlobalPackageVersion: z$1.ZodNullable;\n installAction: z$1.ZodNullable;\n label: z$1.ZodEnum<{\n Install: \"Install\";\n Update: \"Update\";\n }>;\n commandKind: z$1.ZodEnum<{\n exec: \"exec\";\n shell: \"shell\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>>;\n needsUpdate: z$1.ZodBoolean;\n versionUnsupported: z$1.ZodBoolean;\n}, z$1.core.$strip>>;\ntype ProviderCliStatusResponse = z$1.infer;\ndeclare const providerCliInstallRequestSchema: z$1.ZodObject<{\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n actionKind: z$1.ZodEnum<{\n install: \"install\";\n update: \"update\";\n }>;\n}, z$1.core.$strip>;\ntype ProviderCliInstallRequest = z$1.infer;\ndeclare const providerCliInstallEventSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"started\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n command: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"output\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n stream: z$1.ZodEnum<{\n stdout: \"stdout\";\n stderr: \"stderr\";\n }>;\n text: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"completed\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n exitCode: z$1.ZodNullable;\n signal: z$1.ZodNullable;\n success: z$1.ZodBoolean;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"error\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>], \"type\">;\ntype ProviderCliInstallEvent = z$1.infer;\n\ninterface CreateFilePreviewResponse {\n baseUrl: string;\n expiresAtMs: number;\n}\ntype HostFileReadResponse = HostDaemonOnlineRpcResultByType[\"host.read_file\"];\ntype HostFileWriteResponse = HostDaemonOnlineRpcResultByType[\"host.write_file\"];\ntype HostFileListResponse = HostDaemonOnlineRpcResultByType[\"host.list_files\"];\ntype HostPathListResponse = HostDaemonOnlineRpcResultByType[\"host.list_paths\"];\ntype HostMkdirResponse = HostDaemonOnlineRpcResultByType[\"host.mkdir\"];\ntype HostMovePathResponse = HostDaemonOnlineRpcResultByType[\"host.move_path\"];\ntype HostRemovePathResponse = HostDaemonOnlineRpcResultByType[\"host.remove_path\"];\n\n/**\n * Query for `GET /hosts/:id/directory`, the interactive path browser's\n * single-level directory read. `path` is an absolute directory on the host;\n * omitting it lists the host's home directory (the daemon resolves it, since a\n * remote caller cannot know the host's home).\n */\ndeclare const hostDirectoryQuerySchema: z$1.ZodObject<{\n path: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype HostDirectoryQuery = z$1.infer;\ndeclare const hostDirectoryListingSchema: z$1.ZodObject<{\n directory: z$1.ZodString;\n parent: z$1.ZodNullable;\n entries: z$1.ZodArray;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype HostDirectoryListing = z$1.infer;\n/** Project name is sent so the daemon can derive its host-local checkout path. */\ndeclare const hostCloneDefaultPathQuerySchema: z$1.ZodObject<{\n projectId: z$1.ZodString;\n}, z$1.core.$strip>;\ntype HostCloneDefaultPathQuery = z$1.infer;\ndeclare const hostCloneDefaultPathResponseSchema: z$1.ZodObject<{\n path: z$1.ZodString;\n}, z$1.core.$strict>;\ntype HostCloneDefaultPathResponse = z$1.infer;\ndeclare const createHostJoinCodeResponseSchema: z$1.ZodObject<{\n joinCode: z$1.ZodString;\n hostId: z$1.ZodString;\n expiresAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype CreateHostJoinCodeResponse = z$1.infer;\ndeclare const updateHostRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateHostRequest = z$1.infer;\ntype HostPathsExistRequest = PathsExistRequest;\ntype HostPathsExistResponse = PathsExistResponse;\ndeclare const hostPickFolderRequestSchema: z$1.ZodObject<{\n clientHostId: z$1.ZodString;\n}, z$1.core.$strict>;\ntype HostPickFolderRequest = z$1.infer;\ntype HostPickFolderResponse = PickFolderResponse;\ntype HostProviderCliStatusResponse = ProviderCliStatusResponse;\ntype HostProviderCliInstallRequest = ProviderCliInstallRequest;\ntype HostProviderCliInstallEvent = ProviderCliInstallEvent;\n\ndeclare const pluginUpdateCheckEntrySchema: z$1.ZodObject<{\n id: z$1.ZodString;\n outcome: z$1.ZodEnum<{\n incompatible: \"incompatible\";\n current: \"current\";\n \"update-available\": \"update-available\";\n pinned: \"pinned\";\n unavailable: \"unavailable\";\n }>;\n devMode: z$1.ZodOptional>;\n installed: z$1.ZodObject<{\n version: z$1.ZodString;\n display: z$1.ZodString;\n }, z$1.core.$strip>;\n candidate: z$1.ZodOptional>;\n blocked: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n detail: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PluginUpdateCheckEntry = z$1.infer;\ndeclare const pluginApplyUpdateResultSchema: z$1.ZodObject<{\n applied: z$1.ZodBoolean;\n from: z$1.ZodObject<{\n version: z$1.ZodString;\n display: z$1.ZodString;\n }, z$1.core.$strip>;\n to: z$1.ZodOptional>;\n outcome: z$1.ZodEnum<{\n current: \"current\";\n updated: \"updated\";\n \"rolled-back\": \"rolled-back\";\n }>;\n detail: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PluginApplyUpdateResult$1 = z$1.infer;\ndeclare const pluginSourceDetailSchema: z$1.ZodObject<{\n requested: z$1.ZodString;\n resolved: z$1.ZodString;\n integrity: z$1.ZodOptional;\n registry: z$1.ZodOptional;\n engines: z$1.ZodObject<{\n bb: z$1.ZodOptional;\n bbPluginSdk: z$1.ZodOptional;\n }, z$1.core.$strip>;\n installedAt: z$1.ZodOptional;\n history: z$1.ZodArray>;\n}, z$1.core.$strip>;\ntype PluginSourceDetail = z$1.infer;\ndeclare const installedPluginSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n source: z$1.ZodString;\n rootDir: z$1.ZodString;\n version: z$1.ZodString;\n provenance: z$1.ZodEnum<{\n builtin: \"builtin\";\n direct: \"direct\";\n catalog: \"catalog\";\n }>;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n incompatible: \"incompatible\";\n missing: \"missing\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype InstalledPlugin = z$1.infer;\ndeclare const pluginListResponseSchema: z$1.ZodObject<{\n enabled: z$1.ZodBoolean;\n plugins: z$1.ZodArray;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n incompatible: \"incompatible\";\n missing: \"missing\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginListResponse = z$1.infer;\ndeclare const pluginReloadResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n plugins: z$1.ZodArray;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n incompatible: \"incompatible\";\n missing: \"missing\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginReloadResponse = z$1.infer;\ndeclare const pluginRemoveResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n}, z$1.core.$strip>;\ntype PluginRemoveResponse = z$1.infer;\ndeclare const pluginSettingsResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n schema: z$1.ZodRecord;\n secret: z$1.ZodOptional>;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"boolean\">;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"select\">;\n options: z$1.ZodArray;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project\">;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>], \"type\">>;\n values: z$1.ZodRecord>>;\n}, z$1.core.$strip>;\ntype PluginSettingsResponse = z$1.infer;\ndeclare const pluginTokenResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n token: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PluginTokenResponse = z$1.infer;\ndeclare const pluginCatalogStatusSchema: z$1.ZodObject<{\n pluginCount: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype PluginCatalogStatus = z$1.infer;\ndeclare const pluginCatalogSearchResultSchema: z$1.ZodObject<{\n entryId: z$1.ZodString;\n displayName: z$1.ZodString;\n description: z$1.ZodString;\n icon: z$1.ZodNullable;\n category: z$1.ZodString;\n source: z$1.ZodString;\n installed: z$1.ZodBoolean;\n compatible: z$1.ZodBoolean;\n incompatibleReason: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype PluginCatalogSearchResult$1 = z$1.infer;\n\ndeclare const systemExecutionOptionsResponseSchema: z$1.ZodObject<{\n providers: z$1.ZodArray;\n capabilities: z$1.ZodObject<{\n supportsArchive: z$1.ZodBoolean;\n supportsRename: z$1.ZodBoolean;\n supportsServiceTier: z$1.ZodBoolean;\n supportsUserQuestion: z$1.ZodBoolean;\n supportsFork: z$1.ZodBoolean;\n supportedPermissionModes: z$1.ZodArray>;\n }, z$1.core.$strip>;\n composerActions: z$1.ZodArray;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plan\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"goal\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>], \"kind\">>;\n available: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n models: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n selectedOnlyModels: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n modelLoadError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype SystemExecutionOptionsResponse = z$1.infer;\ndeclare const systemExecutionOptionsQuerySchema: z$1.ZodObject<{\n providerId: z$1.ZodOptional;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SystemExecutionOptionsQuery = z$1.infer;\n/** Omission preserves the existing behavior of reading the primary machine. */\ndeclare const systemUsageLimitsQuerySchema: z$1.ZodObject<{\n hostId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SystemUsageLimitsQuery = z$1.infer;\ndeclare const systemVoiceTranscriptionResponseSchema: z$1.ZodObject<{\n text: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemVoiceTranscriptionResponse = z$1.infer;\ndeclare const systemConfigResponseSchema: z$1.ZodObject<{\n generalSettings: z$1.ZodObject<{\n caffeinate: z$1.ZodBoolean;\n showKeyboardHints: z$1.ZodBoolean;\n showUnhandledProviderEvents: z$1.ZodBoolean;\n codexMemoryEnabled: z$1.ZodBoolean;\n claudeCodeMemoryEnabled: z$1.ZodBoolean;\n codexSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeWorkflowsDisabled: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n keybindings: z$1.ZodArray;\n desktopOnly: z$1.ZodBoolean;\n shortcut: z$1.ZodObject<{\n key: z$1.ZodString;\n mod: z$1.ZodBoolean;\n meta: z$1.ZodBoolean;\n control: z$1.ZodBoolean;\n alt: z$1.ZodBoolean;\n shift: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n when: z$1.ZodObject<{\n all: z$1.ZodArray>;\n none: z$1.ZodArray>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>>;\n defaultKeybindings: z$1.ZodArray;\n desktopOnly: z$1.ZodBoolean;\n shortcut: z$1.ZodObject<{\n key: z$1.ZodString;\n mod: z$1.ZodBoolean;\n meta: z$1.ZodBoolean;\n control: z$1.ZodBoolean;\n alt: z$1.ZodBoolean;\n shift: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n when: z$1.ZodObject<{\n all: z$1.ZodArray>;\n none: z$1.ZodArray>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>>;\n keybindingOverrides: z$1.ZodArray;\n shortcut: z$1.ZodNullable>;\n }, z$1.core.$strict>>;\n experiments: z$1.ZodObject<{\n claudeCodeMockCliTraffic: z$1.ZodBoolean;\n plugins: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n appearance: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n }, z$1.core.$strip>;\n customThemes: z$1.ZodArray;\n pluginThemes: z$1.ZodArray;\n }, z$1.core.$strip>>;\n featureFlags: z$1.ZodObject<{\n placeholder: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n hostDaemonPort: z$1.ZodNullable;\n primaryHostId: z$1.ZodNullable;\n primaryHostPlatform: z$1.ZodNullable>;\n voiceTranscriptionEnabled: z$1.ZodBoolean;\n dataDir: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemConfigResponse = z$1.infer;\ndeclare const systemAttentionResponseSchema: z$1.ZodObject<{\n hasAttention: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype SystemAttentionResponse = z$1.infer;\n/**\n * Theme catalog: the on-disk custom-theme directory plus the discovered custom\n * themes and the active palette. Drives `bb theme list` / `bb theme dir`.\n */\ndeclare const themeCatalogResponseSchema: z$1.ZodObject<{\n dir: z$1.ZodString;\n custom: z$1.ZodArray;\n plugins: z$1.ZodArray;\n }, z$1.core.$strip>>;\n active: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>;\ntype ThemeCatalogResponse = z$1.infer;\ndeclare const systemVersionResponseSchema: z$1.ZodObject<{\n currentVersion: z$1.ZodString;\n latestVersion: z$1.ZodNullable;\n source: z$1.ZodLiteral<\"npm\">;\n updateAvailable: z$1.ZodBoolean;\n isDevelopment: z$1.ZodBoolean;\n upgradeCommand: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemVersionResponse = z$1.infer;\ndeclare const systemConfigReloadResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n}, z$1.core.$strip>;\ntype SystemConfigReloadResponse = z$1.infer;\n\ndeclare const terminalSessionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodNullable;\n environmentId: z$1.ZodNullable;\n hostId: z$1.ZodString;\n title: z$1.ZodString;\n initialCwd: z$1.ZodString;\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n status: z$1.ZodEnum<{\n running: \"running\";\n starting: \"starting\";\n disconnected: \"disconnected\";\n exited: \"exited\";\n }>;\n exitCode: z$1.ZodNullable;\n closeReason: z$1.ZodNullable>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n lastUserInputAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TerminalSession = z$1.infer;\ndeclare const terminalListResponseSchema: z$1.ZodObject<{\n sessions: z$1.ZodArray;\n environmentId: z$1.ZodNullable;\n hostId: z$1.ZodString;\n title: z$1.ZodString;\n initialCwd: z$1.ZodString;\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n status: z$1.ZodEnum<{\n running: \"running\";\n starting: \"starting\";\n disconnected: \"disconnected\";\n exited: \"exited\";\n }>;\n exitCode: z$1.ZodNullable;\n closeReason: z$1.ZodNullable>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n lastUserInputAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype TerminalListResponse = z$1.infer;\ndeclare const createTerminalRequestSchema: z$1.ZodObject<{\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n start: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"command\">;\n command: z$1.ZodString;\n }, z$1.core.$strict>], \"mode\">>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"environment\">;\n environmentId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"host_path\">;\n hostId: z$1.ZodString;\n cwd: z$1.ZodNullable;\n }, z$1.core.$strict>], \"kind\">;\n title: z$1.ZodOptional;\n}, z$1.core.$strict>;\ntype CreateTerminalRequest = z$1.infer;\ndeclare const updateTerminalRequestSchema: z$1.ZodObject<{\n title: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateTerminalRequest = z$1.infer;\ndeclare const terminalInputRequestSchema: z$1.ZodObject<{\n dataBase64: z$1.ZodString;\n}, z$1.core.$strict>;\ntype TerminalInputRequest = z$1.infer;\ndeclare const terminalResizeRequestSchema: z$1.ZodObject<{\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype TerminalResizeRequest = z$1.infer;\ndeclare const terminalOutputQuerySchema: z$1.ZodObject<{\n sinceSeq: z$1.ZodOptional>;\n tailBytes: z$1.ZodOptional>;\n limitChunks: z$1.ZodOptional>;\n}, z$1.core.$strict>;\ntype TerminalOutputQuery = z$1.infer;\ndeclare const terminalOutputResponseSchema: z$1.ZodObject<{\n chunks: z$1.ZodArray>;\n nextSeq: z$1.ZodNumber;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strict>;\ntype TerminalOutputResponse = z$1.infer;\n\ndeclare const timelineRowStatusSchema: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n}>;\ntype TimelineRowStatus = z$1.infer;\ndeclare const timelineRowBaseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype TimelineRowBase = z$1.infer;\ndeclare const timelineConversationRowSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"conversation\">;\n text: z$1.ZodString;\n attachments: z$1.ZodNullable;\n localImagePaths: z$1.ZodArray;\n localFilePaths: z$1.ZodArray;\n }, z$1.core.$strip>>;\n role: z$1.ZodLiteral<\"user\">;\n initiator: z$1.ZodEnum<{\n user: \"user\";\n agent: \"agent\";\n system: \"system\";\n }>;\n senderThreadId: z$1.ZodNullable;\n actorHandle: z$1.ZodDefault>;\n systemMessageKind: z$1.ZodEnum<{\n \"ownership-assigned\": \"ownership-assigned\";\n \"ownership-removed\": \"ownership-removed\";\n \"child-needs-attention\": \"child-needs-attention\";\n \"child-completed\": \"child-completed\";\n \"child-failed\": \"child-failed\";\n \"child-interrupted\": \"child-interrupted\";\n \"child-outcome-batch\": \"child-outcome-batch\";\n unlabeled: \"unlabeled\";\n }>;\n systemMessageSubject: z$1.ZodNullable;\n threadId: z$1.ZodString;\n threadName: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-batch\">;\n count: z$1.ZodNumber;\n }, z$1.core.$strip>], \"kind\">>;\n turnRequest: z$1.ZodObject<{\n kind: z$1.ZodEnum<{\n message: \"message\";\n steer: \"steer\";\n }>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n accepted: \"accepted\";\n }>;\n }, z$1.core.$strip>;\n mentions: z$1.ZodArray, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"conversation\">;\n text: z$1.ZodString;\n attachments: z$1.ZodNullable;\n localImagePaths: z$1.ZodArray;\n localFilePaths: z$1.ZodArray;\n }, z$1.core.$strip>>;\n role: z$1.ZodLiteral<\"assistant\">;\n turnRequest: z$1.ZodNull;\n}, z$1.core.$strip>], \"role\">;\ntype TimelineConversationRow = z$1.infer;\ndeclare const timelineSystemRowSchema: z$1.ZodUnion;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n status: z$1.ZodNullable>;\n systemKind: z$1.ZodEnum<{\n error: \"error\";\n debug: \"debug\";\n reconnect: \"reconnect\";\n }>;\n}, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n status: z$1.ZodNullable>;\n systemKind: z$1.ZodLiteral<\"operation\">;\n operationKind: z$1.ZodEnum<{\n generic: \"generic\";\n compaction: \"compaction\";\n \"thread-provisioning\": \"thread-provisioning\";\n \"thread-interrupted\": \"thread-interrupted\";\n \"provider-unhandled\": \"provider-unhandled\";\n warning: \"warning\";\n deprecation: \"deprecation\";\n }>;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n systemKind: z$1.ZodLiteral<\"operation\">;\n operationKind: z$1.ZodLiteral<\"parent-change\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n parentChange: z$1.ZodObject<{\n action: z$1.ZodEnum<{\n assign: \"assign\";\n release: \"release\";\n transfer: \"transfer\";\n }>;\n previousParentThreadId: z$1.ZodNullable;\n previousParentThreadTitle: z$1.ZodNullable;\n nextParentThreadId: z$1.ZodNullable;\n nextParentThreadTitle: z$1.ZodNullable;\n }, z$1.core.$strip>;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>], \"operationKind\">]>;\ntype TimelineSystemRow = z$1.infer;\ninterface TimelineWorkRowBase extends TimelineRowBase {\n kind: \"work\";\n status: TimelineRowStatus;\n}\ndeclare const timelineCommandWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"command\">;\n callId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n source: z$1.ZodNullable;\n output: z$1.ZodString;\n exitCode: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n activityIntents: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"list_files\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype TimelineCommandWorkRow = z$1.infer;\ndeclare const timelineToolWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"tool\">;\n callId: z$1.ZodString;\n toolName: z$1.ZodString;\n toolArgs: z$1.ZodNullable>>>;\n output: z$1.ZodString;\n completedAt: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n activityIntents: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"list_files\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype TimelineToolWorkRow = z$1.infer;\ndeclare const timelineFileChangeWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"file-change\">;\n callId: z$1.ZodString;\n change: z$1.ZodObject<{\n path: z$1.ZodString;\n kind: z$1.ZodNullable;\n movePath: z$1.ZodNullable;\n diff: z$1.ZodNullable;\n diffStats: z$1.ZodObject<{\n added: z$1.ZodNumber;\n removed: z$1.ZodNumber;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>;\n stdout: z$1.ZodNullable;\n stderr: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n}, z$1.core.$strip>;\ntype TimelineFileChangeWorkRow = z$1.infer;\ndeclare const timelineWebSearchWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"web-search\">;\n callId: z$1.ZodString;\n queries: z$1.ZodArray;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWebSearchWorkRow = z$1.infer;\ndeclare const timelineWebFetchWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"web-fetch\">;\n callId: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWebFetchWorkRow = z$1.infer;\ndeclare const timelineImageViewWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"image-view\">;\n callId: z$1.ZodString;\n path: z$1.ZodString;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineImageViewWorkRow = z$1.infer;\ndeclare const timelineApprovalWorkRowSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"approval\">;\n interactionId: z$1.ZodString;\n target: z$1.ZodObject<{\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n }, z$1.core.$strip>;\n approvalKind: z$1.ZodLiteral<\"file-edit\">;\n lifecycle: z$1.ZodEnum<{\n denied: \"denied\";\n waiting: \"waiting\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"approval\">;\n interactionId: z$1.ZodString;\n target: z$1.ZodObject<{\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n }, z$1.core.$strip>;\n approvalKind: z$1.ZodLiteral<\"permission-grant\">;\n lifecycle: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n denied: \"denied\";\n resolving: \"resolving\";\n granted: \"granted\";\n }>;\n grantScope: z$1.ZodNullable>;\n statusReason: z$1.ZodNullable;\n}, z$1.core.$strip>], \"approvalKind\">;\ntype TimelineApprovalWorkRow = z$1.infer;\ndeclare const timelineQuestionWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"question\">;\n interactionId: z$1.ZodString;\n lifecycle: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n answered: \"answered\";\n }>;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n answers: z$1.ZodNullable;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n statusReason: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineQuestionWorkRow = z$1.infer;\ninterface TimelineDelegationWorkRow extends TimelineWorkRowBase {\n workKind: \"delegation\";\n callId: string;\n toolName: string;\n subagentType: string | null;\n description: string | null;\n output: string;\n completedAt: number | null;\n childRows: TimelineRow[];\n}\n/**\n * A provider background task — a dynamic workflow (Claude Code Workflow tool)\n * or a backgrounded shell command (Bash run_in_background), discriminated by\n * `taskType`. The row outlives its spawning turn: progress and terminal state\n * arrive via thread-scoped events folded into this single row. `workflow` is\n * the merged phase/agent tree, present only for workflows; null for shell\n * commands and for workflows the provider reported no progress records for\n * (degraded rendering falls back to description + summary).\n */\ndeclare const timelineWorkflowWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWorkflowWorkRow = z$1.infer;\ntype TimelineWorkRow = TimelineCommandWorkRow | TimelineToolWorkRow | TimelineFileChangeWorkRow | TimelineWebSearchWorkRow | TimelineWebFetchWorkRow | TimelineImageViewWorkRow | TimelineApprovalWorkRow | TimelineQuestionWorkRow | TimelineDelegationWorkRow | TimelineWorkflowWorkRow;\ninterface TimelineTurnRow extends TimelineRowBase {\n kind: \"turn\";\n turnId: string;\n status: TimelineRowStatus;\n summaryCount: number;\n completedAt: number | null;\n children: TimelineRow[] | null;\n}\ntype TimelineSourceRow = TimelineConversationRow | TimelineWorkRow | TimelineSystemRow;\ntype TimelineRow = TimelineSourceRow | TimelineTurnRow;\n\ndeclare const createThreadRequestSchema: z$1.ZodObject<{\n projectId: z$1.ZodString;\n providerId: z$1.ZodOptional;\n origin: z$1.ZodEnum<{\n plugin: \"plugin\";\n app: \"app\";\n cli: \"cli\";\n sdk: \"sdk\";\n }>;\n originPluginId: z$1.ZodOptional;\n visibility: z$1.ZodOptional>;\n title: z$1.ZodOptional;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n model: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n environment: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reuse\">;\n environmentId: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host\">;\n hostId: z$1.ZodOptional;\n workspace: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unmanaged\">;\n path: z$1.ZodNullable;\n branch: z$1.ZodOptional;\n name: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new\">;\n baseBranch: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"managed-worktree\">;\n baseBranch: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"named\">;\n name: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"default\">;\n }, z$1.core.$strip>], \"kind\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"personal\">;\n }, z$1.core.$strip>], \"type\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project-default\">;\n }, z$1.core.$strip>], \"type\">;\n parentThreadId: z$1.ZodOptional;\n sectionId: z$1.ZodOptional>;\n sourceThreadId: z$1.ZodOptional;\n sourceSeqEnd: z$1.ZodOptional;\n startedOnBehalfOf: z$1.ZodDefault;\n senderThreadId: z$1.ZodString;\n }, z$1.core.$strip>>>;\n originKind: z$1.ZodDefault>>;\n childOrigin: z$1.ZodDefault>>;\n}, z$1.core.$strip>;\ntype CreateThreadRequest = z$1.infer;\ndeclare const sendMessageRequestSchema: z$1.ZodObject<{\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n mode: z$1.ZodEnum<{\n steer: \"steer\";\n start: \"start\";\n auto: \"auto\";\n \"queue-if-active\": \"queue-if-active\";\n \"steer-if-active\": \"steer-if-active\";\n }>;\n senderThreadId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SendMessageRequest = z$1.infer;\ndeclare const createQueuedMessageRequestSchema: z$1.ZodObject<{\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n senderThreadId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype CreateQueuedMessageRequest = z$1.infer;\ndeclare const updateQueuedMessageRequestSchema: z$1.ZodObject<{\n expectedUpdatedAt: z$1.ZodNumber;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype UpdateQueuedMessageRequest = z$1.infer;\ndeclare const sendQueuedMessageRequestSchema: z$1.ZodObject<{\n mode: z$1.ZodEnum<{\n steer: \"steer\";\n auto: \"auto\";\n }>;\n}, z$1.core.$strip>;\ntype SendQueuedMessageRequest = z$1.infer;\ndeclare const reorderQueuedMessageRequestSchema: z$1.ZodObject<{\n previousQueuedMessageId: z$1.ZodNullable;\n nextQueuedMessageId: z$1.ZodNullable;\n groupBoundaryQueuedMessageId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ReorderQueuedMessageRequest = z$1.infer;\ndeclare const setQueuedMessageGroupBoundaryRequestSchema: z$1.ZodObject<{\n expectedGroupedPrefixQueuedMessageIds: z$1.ZodArray;\n groupBoundaryQueuedMessageId: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SetQueuedMessageGroupBoundaryRequest = z$1.infer;\ndeclare const sendQueuedMessageResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n queuedMessage: z$1.ZodObject<{\n id: z$1.ZodString;\n content: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>;\ntype SendQueuedMessageResponse = z$1.infer;\ndeclare const threadListResponseSchema: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n}, z$1.core.$strip>>;\ntype ThreadListResponse = z$1.infer;\ndeclare const threadSearchResponseSchema: z$1.ZodObject<{\n active: z$1.ZodObject<{\n total: z$1.ZodNumber;\n results: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>;\n matches: z$1.ZodArray;\n text: z$1.ZodString;\n highlightRanges: z$1.ZodArray>;\n sourceSeq: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>;\n archived: z$1.ZodObject<{\n total: z$1.ZodNumber;\n results: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>;\n matches: z$1.ZodArray;\n text: z$1.ZodString;\n highlightRanges: z$1.ZodArray>;\n sourceSeq: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>;\ntype ThreadSearchResponse = z$1.infer;\ndeclare const threadResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n environmentId: z$1.ZodNullable;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n canSpawnChild: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype ThreadResponse = z$1.infer;\ndeclare const threadGetQuerySchema: z$1.ZodObject<{\n include: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadGetQuery = z$1.infer;\ndeclare const threadWithIncludesResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n environmentId: z$1.ZodNullable;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n canSpawnChild: z$1.ZodBoolean;\n environment: z$1.ZodOptional;\n projectId: z$1.ZodString;\n hostId: z$1.ZodString;\n path: z$1.ZodNullable;\n managed: z$1.ZodBoolean;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n branchName: z$1.ZodNullable;\n baseBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n mergeBaseBranch: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n ready: \"ready\";\n retiring: \"retiring\";\n destroying: \"destroying\";\n destroyed: \"destroyed\";\n }>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>>>;\n host: z$1.ZodOptional;\n status: z$1.ZodEnum<{\n disconnected: \"disconnected\";\n connected: \"connected\";\n }>;\n lastSeenAt: z$1.ZodNullable;\n lastRejectedProtocolVersion: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>>>;\n}, z$1.core.$strip>;\ntype ThreadWithIncludesResponse = z$1.infer;\ndeclare const threadPendingInteractionsResponseSchema: z$1.ZodArray;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n origin: z$1.ZodOptional;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n }, z$1.core.$strip>>;\n payload: z$1.ZodUnion;\n subject: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n itemId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n actions: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"listFiles\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"file_change\">;\n itemId: z$1.ZodString;\n writeScope: z$1.ZodNullable;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>], \"kind\">;\n reason: z$1.ZodNullable;\n availableDecisions: z$1.ZodArray>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>;\n resolution: z$1.ZodNullable;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodNullable;\n origin: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n rendererId: z$1.ZodString;\n }, z$1.core.$strip>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n title: z$1.ZodString;\n data: z$1.ZodType>;\n }, z$1.core.$strip>;\n resolution: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>]>>;\ntype ThreadPendingInteractionsResponse = z$1.infer;\ndeclare const threadQueuedMessageListResponseSchema: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>>;\ntype ThreadQueuedMessageListResponse = z$1.infer;\ndeclare const threadChildSummaryResponseSchema: z$1.ZodObject<{\n nonDeletedChildCount: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadChildSummaryResponse = z$1.infer;\ndeclare const deleteThreadRequestSchema: z$1.ZodObject<{\n childThreadsConfirmed: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype DeleteThreadRequest = z$1.infer;\ndeclare const updateThreadRequestSchema: z$1.ZodObject<{\n title: z$1.ZodOptional>;\n sectionId: z$1.ZodOptional>;\n parentThreadId: z$1.ZodOptional>;\n model: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype UpdateThreadRequest = z$1.infer;\ndeclare const reorderPinnedThreadRequestSchema: z$1.ZodObject<{\n previousThreadId: z$1.ZodNullable;\n nextThreadId: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ReorderPinnedThreadRequest = z$1.infer;\n/**\n * Requested placement for a thread opened in the app's split layout. Edge\n * placements add panes through the eighth pane; at the cap they replace the\n * focused pane. `replace` always replaces the focused pane.\n */\ndeclare const threadOpenSplitSchema: z$1.ZodEnum<{\n right: \"right\";\n down: \"down\";\n left: \"left\";\n top: \"top\";\n replace: \"replace\";\n}>;\ntype ThreadOpenSplit = z$1.infer;\n/** Optional secondary-panel file to open with a thread. */\ndeclare const threadOpenFileSchema: z$1.ZodObject<{\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n path: z$1.ZodString;\n lineNumber: z$1.ZodNullable;\n}, z$1.core.$strict>;\ntype ThreadOpenFile = z$1.infer;\n/** Response for POST /threads/:id/open: how many connected clients received it. */\ndeclare const threadOpenResponseSchema: z$1.ZodObject<{\n delivered: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadOpenResponse = z$1.infer;\n/** Presentation action for one thread pane in each connected app window. */\ndeclare const threadPaneActionSchema: z$1.ZodEnum<{\n maximize: \"maximize\";\n restore: \"restore\";\n toggle: \"toggle\";\n}>;\ntype ThreadPaneAction = z$1.infer;\n/** Number of connected app clients that received the pane action. */\ndeclare const threadPaneActionResponseSchema: z$1.ZodObject<{\n delivered: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadPaneActionResponse = z$1.infer;\ndeclare const threadArchiveAllResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n archivedThreadIds: z$1.ZodArray;\n}, z$1.core.$strip>;\ntype ThreadArchiveAllResponse = z$1.infer;\ndeclare const threadListQuerySchema: z$1.ZodObject<{\n projectId: z$1.ZodOptional;\n parentThreadId: z$1.ZodOptional;\n sourceThreadId: z$1.ZodOptional;\n archived: z$1.ZodOptional>;\n sectionId: z$1.ZodOptional;\n unsectioned: z$1.ZodOptional>;\n hasParent: z$1.ZodOptional>;\n originKind: z$1.ZodOptional>;\n excludeSideChats: z$1.ZodOptional>;\n childOrigin: z$1.ZodOptional>;\n limit: z$1.ZodOptional;\n offset: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadListQuery = z$1.infer;\ndeclare const threadSearchQuerySchema: z$1.ZodObject<{\n query: z$1.ZodString;\n limitPerGroup: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadSearchQuery = z$1.infer;\ndeclare const threadTimelineQuerySchema: z$1.ZodObject<{\n includeNestedRows: z$1.ZodOptional>;\n segmentLimit: z$1.ZodOptional;\n beforeAnchorSeq: z$1.ZodOptional;\n beforeAnchorId: z$1.ZodOptional;\n summaryOnly: z$1.ZodOptional>;\n afterSequence: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadTimelineQuery = z$1.infer;\ndeclare const timelineTurnSummaryDetailsQuerySchema: z$1.ZodObject<{\n turnId: z$1.ZodString;\n sourceSeqStart: z$1.ZodString;\n sourceSeqEnd: z$1.ZodString;\n}, z$1.core.$strip>;\ntype TimelineTurnSummaryDetailsQuery = z$1.infer;\ndeclare const threadStorageFilesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadStorageFilesQuery = z$1.infer;\ndeclare const threadStoragePathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n}, z$1.core.$strip>;\ntype ThreadStoragePathsQuery = z$1.infer;\ndeclare const timelineTurnSummaryDetailsResponseSchema: z$1.ZodObject<{\n rows: z$1.ZodArray>>;\n}, z$1.core.$strip>;\ntype TimelineTurnSummaryDetailsResponse = z$1.infer;\ndeclare const threadTimelineResponseSchema: z$1.ZodObject<{\n rows: z$1.ZodArray>>;\n activePromptMode: z$1.ZodNullable;\n providerId: z$1.ZodEnum<{\n codex: \"codex\";\n \"claude-code\": \"claude-code\";\n }>;\n prompt: z$1.ZodString;\n }, z$1.core.$strict>>;\n activeThinking: z$1.ZodNullable>;\n activeWorkflow: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n activeBackgroundCommands: z$1.ZodArray;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n pendingTodos: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n goal: z$1.ZodNullable;\n tokenBudget: z$1.ZodNullable;\n tokensUsed: z$1.ZodNumber;\n timeUsedSeconds: z$1.ZodNumber;\n }, z$1.core.$strip>>;\n modelFallback: z$1.ZodNullable;\n message: z$1.ZodString;\n }, z$1.core.$strip>>;\n contextWindowUsage: z$1.ZodOptional>;\n timelinePage: z$1.ZodObject<{\n kind: z$1.ZodEnum<{\n latest: \"latest\";\n older: \"older\";\n }>;\n segmentLimit: z$1.ZodNumber;\n returnedSegmentCount: z$1.ZodNumber;\n hasOlderRows: z$1.ZodBoolean;\n olderCursor: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n maxSeq: z$1.ZodNumber;\n delta: z$1.ZodOptional>>;\n rowOrder: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ThreadTimelineResponse = z$1.infer;\ndeclare const threadConversationOutlineResponseSchema: z$1.ZodObject<{\n items: z$1.ZodArray;\n preview: z$1.ZodString;\n attachmentSummary: z$1.ZodNullable>;\n }, z$1.core.$strict>>;\n maxSeq: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadConversationOutlineResponse = z$1.infer;\ndeclare const threadStorageFileListResponseSchema: z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n storageRootPath: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ThreadStorageFileListResponse = z$1.infer;\ndeclare const threadStoragePathListResponseSchema: z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n storageRootPath: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ThreadStoragePathListResponse = z$1.infer;\n\ndeclare const threadTabsResponseSchema: z$1.ZodObject<{\n revision: z$1.ZodNumber;\n tabs: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"git-diff\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n actionId: z$1.ZodString;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"plugin-panel\">;\n paramsJson: z$1.ZodNullable;\n pluginId: z$1.ZodString;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n projectId: z$1.ZodNullable;\n source: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"working-tree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"head\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge-base\">;\n ref: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">;\n statusLabel: z$1.ZodNullable>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"host-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n isPinned: z$1.ZodBoolean;\n kind: z$1.ZodLiteral<\"thread-storage-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"browser\">;\n title: z$1.ZodNullable;\n url: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"new-tab\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"side-chat\">;\n sourceMessageText: z$1.ZodString;\n sourceSeqEnd: z$1.ZodNullable;\n threadId: z$1.ZodNullable;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"terminal\">;\n terminalId: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n}, z$1.core.$strict>;\ntype ThreadTabsResponse = z$1.infer;\ndeclare const updateThreadTabsRequestSchema: z$1.ZodObject<{\n expectedRevision: z$1.ZodNumber;\n tabs: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"git-diff\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n actionId: z$1.ZodString;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"plugin-panel\">;\n paramsJson: z$1.ZodNullable;\n pluginId: z$1.ZodString;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n projectId: z$1.ZodNullable;\n source: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"working-tree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"head\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge-base\">;\n ref: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">;\n statusLabel: z$1.ZodNullable>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"host-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n isPinned: z$1.ZodBoolean;\n kind: z$1.ZodLiteral<\"thread-storage-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"browser\">;\n title: z$1.ZodNullable;\n url: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"new-tab\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"side-chat\">;\n sourceMessageText: z$1.ZodString;\n sourceSeqEnd: z$1.ZodNullable;\n threadId: z$1.ZodNullable;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"terminal\">;\n terminalId: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n}, z$1.core.$strict>;\ntype UpdateThreadTabsRequest = z$1.infer;\n\ninterface EnvironmentActionArgs {\n environmentId: string;\n}\ninterface EnvironmentGetArgs extends EnvironmentActionArgs {\n signal?: AbortSignal;\n}\ntype EnvironmentMergeBaseBranchUpdateValue = Exclude;\ntype EnvironmentNameUpdateValue = Exclude;\ninterface EnvironmentMergeBaseBranchUpdate {\n mergeBaseBranch: EnvironmentMergeBaseBranchUpdateValue;\n name?: EnvironmentNameUpdateValue;\n}\ninterface EnvironmentNameUpdate {\n mergeBaseBranch?: EnvironmentMergeBaseBranchUpdateValue;\n name: EnvironmentNameUpdateValue;\n}\ntype EnvironmentUpdateFields = EnvironmentMergeBaseBranchUpdate | EnvironmentNameUpdate;\ntype EnvironmentUpdateArgs = EnvironmentUpdateFields & {\n environmentId: string;\n};\ninterface EnvironmentStatusArgs extends EnvironmentStatusQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ntype EnvironmentDiffArgs = EnvironmentDiffQuery & {\n environmentId: string;\n signal?: AbortSignal;\n};\ntype EnvironmentDiffFileArgs = EnvironmentDiffFileQuery & {\n environmentId: string;\n signal?: AbortSignal;\n};\ninterface EnvironmentDiffBranchesArgs extends EnvironmentDiffBranchesQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ninterface EnvironmentCommitArgs {\n environmentId: string;\n}\ninterface EnvironmentSquashMergeArgs {\n environmentId: string;\n mergeBaseBranch: string;\n}\ninterface EnvironmentPullRequestMergeArgs {\n environmentId: string;\n method: PullRequestMergeMethod;\n}\ntype EnvironmentDiffPatchArgs = EnvironmentDiffPatchRequest & {\n environmentId: string;\n signal?: AbortSignal;\n};\ninterface EnvironmentPathsArgs extends EnvironmentPathsQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ntype EnvironmentArchiveThreadsResult = EnvironmentArchiveThreadsResponse;\ntype EnvironmentCommitResult = CommitActionResponse;\ntype EnvironmentDiffResult = EnvironmentDiffResponse;\ntype EnvironmentDiffBranchesResult = EnvironmentDiffBranchesResponse;\ntype EnvironmentDiffFileResult = EnvironmentDiffFileResponse;\ntype EnvironmentDiffFilesResult = EnvironmentDiffFilesResponse;\ntype EnvironmentDiffPatchResult = EnvironmentDiffPatchResponse;\ntype EnvironmentGetResult = Environment;\ntype EnvironmentMarkPullRequestDraftResult = PullRequestDraftActionResponse;\ntype EnvironmentMarkPullRequestReadyResult = PullRequestReadyActionResponse;\ntype EnvironmentMergePullRequestResult = PullRequestMergeActionResponse;\ntype EnvironmentPathsResult = WorkspacePathListResponse;\ntype EnvironmentPullRequestResult = EnvironmentPullRequestResponse;\ntype EnvironmentSquashMergeResult = SquashMergeActionResponse;\ntype EnvironmentStatusResult = EnvironmentStatusResponse;\ntype EnvironmentUpdateResult = Environment;\ninterface EnvironmentsArea {\n archiveThreads(args: EnvironmentActionArgs): Promise;\n commit(args: EnvironmentCommitArgs): Promise;\n diff(args: EnvironmentDiffArgs): Promise;\n diffBranches(args: EnvironmentDiffBranchesArgs): Promise;\n diffFile(args: EnvironmentDiffFileArgs): Promise;\n diffFiles(args: EnvironmentDiffArgs): Promise;\n diffPatch(args: EnvironmentDiffPatchArgs): Promise;\n get(args: EnvironmentGetArgs): Promise;\n pullRequest(args: EnvironmentGetArgs): Promise;\n markPullRequestDraft(args: EnvironmentActionArgs): Promise;\n markPullRequestReady(args: EnvironmentActionArgs): Promise;\n mergePullRequest(args: EnvironmentPullRequestMergeArgs): Promise;\n paths(args: EnvironmentPathsArgs): Promise;\n squashMerge(args: EnvironmentSquashMergeArgs): Promise;\n status(args: EnvironmentStatusArgs): Promise;\n update(args: EnvironmentUpdateArgs): Promise;\n}\n\n/**\n * Host file primitives. `hostId` may be omitted to target the server's\n * primary (local) host. `rootPath`, when set, confines the target beneath\n * that absolute root on the host (symlink-safe).\n */\ninterface FileReadArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n signal?: AbortSignal;\n}\ninterface FileWriteArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n content: string;\n /** Defaults to \"utf8\". */\n contentEncoding?: \"utf8\" | \"base64\";\n /** Defaults to false. */\n createParents?: boolean;\n /**\n * Optimistic-concurrency guard: omitted → unconditional write; a hash →\n * write only when the current content hashes to it (use `read().sha256`);\n * null → create-only. A failed guard resolves to the `conflict` outcome.\n */\n expectedSha256?: string | null;\n /** POSIX permission bits used when creating a file (for example 0o600). */\n mode?: number;\n}\ninterface FileListArgs {\n hostId?: string;\n path: string;\n query?: string;\n limit?: number;\n signal?: AbortSignal;\n}\ninterface PathListArgs extends FileListArgs {\n includeFiles: boolean;\n includeDirectories: boolean;\n}\ninterface FileMkdirArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n recursive?: boolean;\n}\ninterface FileMoveArgs {\n hostId?: string;\n sourcePath: string;\n destinationPath: string;\n rootPath?: string;\n}\ninterface FileRemoveArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n recursive?: boolean;\n}\ninterface FilePreviewArgs {\n hostId?: string;\n rootPath: string;\n signal?: AbortSignal;\n ttlMs?: number;\n}\ntype FileReadResult = HostFileReadResponse;\ntype FileWriteResult = HostFileWriteResponse;\ntype FileListResult = HostFileListResponse;\ntype PathListResult = HostPathListResponse;\ntype FileMkdirResult = HostMkdirResponse;\ntype FileMoveResult = HostMovePathResponse;\ntype FileRemoveResult = HostRemovePathResponse;\ntype FilePreviewResult = CreateFilePreviewResponse;\ninterface FilesArea {\n read(args: FileReadArgs): Promise;\n write(args: FileWriteArgs): Promise;\n list(args: FileListArgs): Promise;\n listPaths(args: PathListArgs): Promise;\n mkdir(args: FileMkdirArgs): Promise;\n move(args: FileMoveArgs): Promise;\n remove(args: FileRemoveArgs): Promise;\n createPreview(args: FilePreviewArgs): Promise;\n}\n\ninterface GuideRenderArgs {\n chapter?: string;\n}\ninterface GuideRenderResult {\n chapter?: string;\n content: string;\n}\ninterface GuideArea {\n render(args?: GuideRenderArgs): GuideRenderResult;\n}\n\ninterface HostGetArgs {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostDeleteArgs {\n hostId: string;\n}\ninterface HostUpdateArgs extends UpdateHostRequest {\n hostId: string;\n}\ninterface HostDirectoryArgs extends HostDirectoryQuery {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostCloneDefaultPathArgs extends HostCloneDefaultPathQuery {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostPathsExistArgs extends HostPathsExistRequest {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostPickFolderArgs extends HostPickFolderRequest {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostProviderCliInstallArgs extends HostProviderCliInstallRequest {\n hostId: string;\n}\ninterface HostListArgs {\n signal?: AbortSignal;\n}\ntype HostCreateJoinCodeResult = CreateHostJoinCodeResponse;\ntype HostDeleteResult = {\n ok: true;\n};\ntype HostDirectoryResult = HostDirectoryListing;\ntype HostGetResult = Host;\ntype HostCloneDefaultPathResult = HostCloneDefaultPathResponse;\ntype HostProviderCliInstallResult = HostProviderCliInstallEvent[];\ntype HostListResult = Host[];\ntype HostPathsExistResult = HostPathsExistResponse;\ntype HostPickFolderResult = HostPickFolderResponse;\ntype HostProviderCliStatusResult = HostProviderCliStatusResponse;\ntype HostUpdateResult = Host;\ninterface HostsArea {\n createJoinCode(): Promise;\n delete(args: HostDeleteArgs): Promise;\n directory(args: HostDirectoryArgs): Promise;\n get(args: HostGetArgs): Promise;\n cloneDefaultPath(args: HostCloneDefaultPathArgs): Promise;\n installProviderCli(args: HostProviderCliInstallArgs): Promise;\n list(args?: HostListArgs): Promise;\n pathsExist(args: HostPathsExistArgs): Promise;\n pickFolder(args: HostPickFolderArgs): Promise;\n providerCliStatus(args: HostGetArgs): Promise;\n update(args: HostUpdateArgs): Promise;\n}\n\ninterface ProjectListArgs {\n include?: ProjectListQuery[\"include\"];\n /** Include the singleton personal project. Defaults to false for compatibility. */\n includePersonal?: boolean;\n signal?: AbortSignal;\n}\ninterface ProjectCreateArgs extends CreateProjectRequest {\n}\ninterface ProjectGetArgs {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectUpdateArgs extends UpdateProjectRequest {\n projectId: string;\n}\ninterface ProjectDeleteArgs {\n projectId: string;\n}\ninterface ProjectReorderArgs extends ReorderProjectRequest {\n projectId: string;\n}\ninterface ProjectPromptHistoryArgs extends PromptHistoryQuery {\n projectId: string;\n signal?: AbortSignal;\n}\n/** Select one project workspace source, or omit both for the primary host. */\ntype ProjectWorkspaceRoutingArgs = {\n environmentId: string;\n hostId?: never;\n} | {\n environmentId?: never;\n hostId: string;\n} | {\n environmentId?: never;\n hostId?: never;\n};\ntype ProjectFilesArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectPathsArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectCommandsArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectFileContentArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ninterface ProjectBranchesArgs extends ProjectBranchesQuery {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectDefaultExecutionOptionsArgs {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectAttachmentFileLike {\n arrayBuffer(): Promise;\n readonly name: string;\n readonly type?: string;\n}\ninterface ProjectAttachmentUploadArgsBase {\n /** MIME override. Omit to use the File/Blob type, when available. */\n mimeType?: string;\n projectId: string;\n}\n/**\n * Upload bytes owned by this SDK client. A bare Blob/byte buffer needs an\n * explicit filename; File-like values can supply their own name.\n */\ntype ProjectAttachmentUploadArgs = ProjectAttachmentUploadArgsBase & ({\n clientFile: ProjectAttachmentFileLike;\n filename?: string;\n} | {\n clientFile: ArrayBuffer | Blob | Uint8Array;\n filename: string;\n});\ninterface ProjectAttachmentReadArgs {\n path: string;\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectAttachmentCopyArgs extends CopyProjectAttachmentsRequest {\n projectId: string;\n}\ntype ProjectSourceAddArgs = CreateProjectSourceRequest & {\n projectId: string;\n};\ninterface ProjectSourceUpdateArgs extends UpdateProjectSourceRequest {\n projectId: string;\n sourceId: string;\n}\ninterface ProjectSourceDeleteArgs {\n projectId: string;\n sourceId: string;\n}\ntype ProjectBranchesResult = ProjectBranchesResponse;\ninterface ProjectAttachmentReadResult {\n bytes: Uint8Array;\n mimeType: string;\n sizeBytes: number;\n}\ntype ProjectAttachmentUploadResult = UploadedPromptAttachment;\ntype ProjectCommandsResult = CommandListResponse;\ntype ProjectCreateResult = ProjectResponse;\ntype ProjectDefaultExecutionOptionsResult = ProjectExecutionDefaults | null;\ntype ProjectDeleteResult = {\n ok: true;\n};\ninterface ProjectFileContentResult {\n /** UTF-8 text or base64, as selected by `contentEncoding`. */\n content: string;\n contentEncoding: \"utf8\" | \"base64\";\n mimeType: string;\n sizeBytes: number;\n}\ntype ProjectFilesResult = WorkspaceFileListResponse;\ntype ProjectGetResult = ProjectResponse;\ntype ProjectListResult = ProjectResponse[] | ProjectWithThreadsResponse[];\ntype ProjectPathsResult = WorkspacePathListResponse;\ntype ProjectPromptHistoryResult = PromptHistoryResponse;\ntype ProjectReorderResult = ProjectResponse[];\ntype ProjectSourceAddResult = ProjectSource;\ntype ProjectSourceDeleteResult = {\n ok: true;\n};\ntype ProjectSourceUpdateResult = ProjectSource;\ntype ProjectUpdateResult = ProjectResponse;\ninterface ProjectSourcesArea {\n add(args: ProjectSourceAddArgs): Promise;\n delete(args: ProjectSourceDeleteArgs): Promise;\n update(args: ProjectSourceUpdateArgs): Promise;\n}\ninterface ProjectAttachmentsArea {\n copy(args: ProjectAttachmentCopyArgs): Promise;\n read(args: ProjectAttachmentReadArgs): Promise;\n upload(args: ProjectAttachmentUploadArgs): Promise;\n}\ninterface ProjectsArea {\n attachments: ProjectAttachmentsArea;\n branches(args: ProjectBranchesArgs): Promise;\n commands(args: ProjectCommandsArgs): Promise;\n create(args: ProjectCreateArgs): Promise;\n defaultExecutionOptions(args: ProjectDefaultExecutionOptionsArgs): Promise;\n delete(args: ProjectDeleteArgs): Promise;\n fileContent(args: ProjectFileContentArgs): Promise;\n files(args: ProjectFilesArgs): Promise;\n get(args: ProjectGetArgs): Promise;\n list(args?: ProjectListArgs): Promise;\n paths(args: ProjectPathsArgs): Promise;\n promptHistory(args: ProjectPromptHistoryArgs): Promise;\n reorder(args: ProjectReorderArgs): Promise;\n sources: ProjectSourcesArea;\n update(args: ProjectUpdateArgs): Promise;\n}\n\n/** Select exactly one provider-discovery host source, or omit both for primary. */\ntype ProviderHostRoutingArgs = {\n environmentId: string;\n hostId?: never;\n} | {\n environmentId?: never;\n hostId: string;\n} | {\n environmentId?: never;\n hostId?: never;\n};\ntype ProviderListArgs = ProviderHostRoutingArgs & {\n signal?: AbortSignal;\n};\ntype ProviderModelsArgs = ProviderHostRoutingArgs & {\n providerId?: string;\n signal?: AbortSignal;\n};\ntype ProviderListResult = ProviderInfo[];\ntype ProviderModelsResult = SystemExecutionOptionsResponse;\ninterface ProvidersArea {\n /** List providers on the environment host, explicit host, or primary host. */\n list(args?: ProviderListArgs): Promise;\n /** List models on the environment host, explicit host, or primary host. */\n models(args?: ProviderModelsArgs): Promise;\n}\n\ninterface PluginIdArgs {\n pluginId: string;\n}\n/** Install directly from a path:, git:, npm:, or builtin: source spec. */\ninterface PluginInstallArgs {\n source: string;\n}\n/** Install an entry from BB's official catalog. */\ninterface PluginCatalogInstallArgs {\n entryId: string;\n}\ninterface PluginReloadArgs {\n pluginId?: string;\n}\ninterface PluginSettingsUpdateArgs extends PluginIdArgs {\n values: Record;\n}\ninterface PluginTokenArgs extends PluginIdArgs {\n rotate?: boolean;\n}\ninterface PluginCheckUpdatesArgs {\n pluginId?: string;\n signal?: AbortSignal;\n}\ninterface PluginRpcArgs extends PluginIdArgs {\n input?: JsonValue;\n method: string;\n outputSchema: z$1.ZodType;\n}\ninterface PluginCatalogSearchArgs {\n query: string;\n signal?: AbortSignal;\n}\ninterface PluginCatalogStatusArgs {\n signal?: AbortSignal;\n}\ninterface PluginGetSettingsArgs extends PluginIdArgs {\n signal?: AbortSignal;\n}\ninterface PluginGetSourceArgs extends PluginIdArgs {\n signal?: AbortSignal;\n}\ninterface PluginListArgs {\n signal?: AbortSignal;\n}\ninterface PluginListUpdateResultsArgs {\n signal?: AbortSignal;\n}\ntype PluginDisableResult = InstalledPlugin;\ntype PluginEnableResult = InstalledPlugin;\ntype PluginGetSettingsResult = PluginSettingsResponse;\ntype PluginInstallResult = InstalledPlugin;\ntype PluginListResult = PluginListResponse;\ntype PluginReloadResult = PluginReloadResponse;\ntype PluginRemoveResult = PluginRemoveResponse;\ntype PluginTokenResult = PluginTokenResponse;\ntype PluginUpdateSettingsResult = PluginSettingsResponse;\ntype PluginGetSourceResult = PluginSourceDetail;\ntype PluginCheckUpdatesResult = PluginUpdateCheckEntry[];\ntype PluginApplyUpdateResult = PluginApplyUpdateResult$1;\ntype PluginCatalogStatusResult = PluginCatalogStatus;\ntype PluginCatalogSearchResult = PluginCatalogSearchResult$1[];\ninterface PluginCatalogArea {\n install(args: PluginCatalogInstallArgs): Promise;\n search(args: PluginCatalogSearchArgs): Promise;\n status(args?: PluginCatalogStatusArgs): Promise;\n}\ninterface PluginsArea {\n applyUpdate(args: PluginIdArgs): Promise;\n callRpc(args: PluginRpcArgs): Promise;\n checkUpdates(args?: PluginCheckUpdatesArgs): Promise;\n catalog: PluginCatalogArea;\n disable(args: PluginIdArgs): Promise;\n enable(args: PluginIdArgs): Promise;\n getSettings(args: PluginGetSettingsArgs): Promise;\n getSource(args: PluginGetSourceArgs): Promise;\n install(args: PluginInstallArgs): Promise;\n list(args?: PluginListArgs): Promise;\n listUpdateResults(args?: PluginListUpdateResultsArgs): Promise;\n reload(args?: PluginReloadArgs): Promise;\n remove(args: PluginIdArgs): Promise;\n token(args: PluginTokenArgs): Promise;\n updateSettings(args: PluginSettingsUpdateArgs): Promise;\n}\n\ntype BbRealtimeUnsubscribe = () => void;\ntype BbRealtimeEventName = \"thread:changed\" | \"project:changed\" | \"environment:changed\" | \"host:changed\" | \"system:changed\" | \"system:config-changed\" | \"realtime:connection\";\ntype ThreadRealtimeEvent = Extract;\ntype ProjectRealtimeEvent = Extract;\ntype EnvironmentRealtimeEvent = Extract;\ntype HostRealtimeEvent = Extract;\ntype SystemRealtimeEvent = Extract;\ntype BbRealtimeConnectionState = \"connecting\" | \"connected\" | \"disconnected\";\ninterface BbRealtimeConnectionEvent {\n reconnectDelayMs: number | null;\n reconnected: boolean;\n state: BbRealtimeConnectionState;\n}\n/**\n * Entity-changed events are delivered as one shared object to every matching\n * listener; their payload types are readonly so a listener cannot mutate what\n * the next listener receives.\n */\ninterface BbRealtimeEventMap {\n \"thread:changed\": ThreadRealtimeEvent;\n \"project:changed\": ProjectRealtimeEvent;\n \"environment:changed\": EnvironmentRealtimeEvent;\n \"host:changed\": HostRealtimeEvent;\n \"system:changed\": SystemRealtimeEvent;\n \"system:config-changed\": SystemRealtimeEvent;\n \"realtime:connection\": BbRealtimeConnectionEvent;\n}\ntype BbRealtimeCallback = (event: BbRealtimeEventMap[TEventName]) => void;\ninterface ThreadRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"thread:changed\">;\n event: \"thread:changed\";\n threadId?: string;\n}\ninterface ProjectRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"project:changed\">;\n event: \"project:changed\";\n projectId?: string;\n}\ninterface EnvironmentRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"environment:changed\">;\n environmentId?: string;\n event: \"environment:changed\";\n}\ninterface HostRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"host:changed\">;\n event: \"host:changed\";\n hostId?: string;\n}\ninterface SystemRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"system:changed\">;\n event: \"system:changed\";\n}\ninterface SystemConfigRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"system:config-changed\">;\n event: \"system:config-changed\";\n}\n/**\n * Connection listeners are pure observers — they never open or hold the\n * socket. A listener registered while a socket already exists receives the\n * latest connection event as a snapshot on the next microtask, so a status\n * UI mounted after connect still learns the current state.\n */\ninterface RealtimeConnectionSubscribeArgs {\n callback: BbRealtimeCallback<\"realtime:connection\">;\n event: \"realtime:connection\";\n}\ntype BbRealtimeSubscribeArgsUnion = ThreadRealtimeSubscribeArgs | ProjectRealtimeSubscribeArgs | EnvironmentRealtimeSubscribeArgs | HostRealtimeSubscribeArgs | SystemRealtimeSubscribeArgs | SystemConfigRealtimeSubscribeArgs | RealtimeConnectionSubscribeArgs;\ntype BbRealtimeSubscribeArgs = Extract;\ninterface BbRealtime {\n subscribe(args: BbRealtimeSubscribeArgs): BbRealtimeUnsubscribe;\n}\n\ninterface StatusGetArgs {\n projectId?: string;\n signal?: AbortSignal;\n threadId?: string;\n}\ninterface StatusThreadSummary {\n environmentId: string | null;\n id: string;\n parentThreadId: string | null;\n pinnedAt: number | null;\n projectId: string;\n status: ThreadStatus;\n title: string | null;\n}\ntype StatusProject = ProjectResponse;\ntype StatusChildThreads = ThreadListResponse;\ninterface StatusResult {\n childThreads: StatusChildThreads | null;\n pendingTodos: ThreadTimelinePendingTodos | null;\n project: StatusProject | null;\n thread: StatusThreadSummary | null;\n}\ninterface StatusArea {\n get(args?: StatusGetArgs): Promise;\n}\n\ntype ThemeGetResult = AppTheme;\ntype ThemeCatalogResult = ThemeCatalogResponse;\ntype ThemeSetInput = AppThemeSelection;\ntype ThemeSetResult = AppTheme;\ninterface ThemeCatalogArgs {\n signal?: AbortSignal;\n}\ninterface ThemeGetArgs {\n signal?: AbortSignal;\n}\ninterface ThemeArea {\n /** The active app palette, resolved server-side (built-in id or custom CSS). */\n get(args?: ThemeGetArgs): Promise;\n /** The custom-theme directory plus discovered themes and the active palette. */\n catalog(args?: ThemeCatalogArgs): Promise;\n /** Set the complete app appearance selection in one request. */\n set(selection: ThemeSetInput): Promise;\n /**\n * Activate a palette by id while preserving the active favicon color. This\n * compatibility shorthand reads the active appearance before writing the\n * complete selection; prefer the object form when both values are known.\n */\n set(themeId: string): Promise;\n}\n\ninterface SystemAttentionArgs {\n signal?: AbortSignal;\n}\ninterface SystemConfigArgs {\n signal?: AbortSignal;\n}\ninterface SystemExecutionOptionsArgs extends SystemExecutionOptionsQuery {\n signal?: AbortSignal;\n}\ninterface SystemUsageLimitsArgs extends SystemUsageLimitsQuery {\n signal?: AbortSignal;\n}\ninterface SystemVersionArgs {\n force?: boolean;\n signal?: AbortSignal;\n}\ninterface SystemVoiceTranscriptionArgs {\n file: Blob;\n prompt?: string;\n signal?: AbortSignal;\n}\ntype SystemAttentionResult = SystemAttentionResponse;\ntype SystemConfigResult = SystemConfigResponse;\ntype SystemExecutionOptionsResult = SystemExecutionOptionsResponse;\ntype SystemReloadConfigResult = SystemConfigReloadResponse;\ntype SystemVoiceTranscriptionResult = SystemVoiceTranscriptionResponse;\ntype SystemUpdateExperimentsResult = Experiments;\ntype SystemUpdateGeneralSettingsResult = AppSettings;\ntype SystemUpdateKeyboardSettingsResult = AppKeybindingOverrides;\ntype SystemUsageLimitsResult = ProviderUsageResponse;\ntype SystemVersionResult = SystemVersionResponse;\ninterface SystemArea {\n attention(args?: SystemAttentionArgs): Promise;\n config(args?: SystemConfigArgs): Promise;\n executionOptions(args?: SystemExecutionOptionsArgs): Promise;\n reloadConfig(): Promise;\n transcribeVoice(args: SystemVoiceTranscriptionArgs): Promise;\n updateExperiments(args: Experiments): Promise;\n updateGeneralSettings(args: AppSettings): Promise;\n updateKeyboardSettings(args: AppKeybindingOverrides): Promise;\n usageLimits(args?: SystemUsageLimitsArgs): Promise;\n version(args?: SystemVersionArgs): Promise;\n}\n\ninterface TerminalThreadScope {\n cwd?: never;\n environmentId?: never;\n hostId?: never;\n kind: \"thread\";\n threadId: string;\n}\ninterface TerminalEnvironmentScope {\n environmentId: string;\n cwd?: never;\n hostId?: never;\n kind: \"environment\";\n threadId?: never;\n}\ninterface TerminalHostPathListScope {\n /** Optional exact initial working-directory filter on the selected host. */\n cwd?: string;\n environmentId?: never;\n hostId: string;\n kind: \"host_path\";\n threadId?: never;\n}\ninterface TerminalHostPathCreateScope {\n /** Null starts in the selected host's home directory. */\n cwd: string | null;\n environmentId?: never;\n hostId: string;\n kind: \"host_path\";\n threadId?: never;\n}\ntype TerminalListScope = TerminalThreadScope | TerminalEnvironmentScope | TerminalHostPathListScope;\ntype TerminalCreateScope = TerminalThreadScope | TerminalEnvironmentScope | TerminalHostPathCreateScope;\ninterface TerminalListArgs {\n signal?: AbortSignal;\n scope: TerminalListScope;\n}\ninterface TerminalCreateArgs {\n cols: number;\n rows: number;\n scope: TerminalCreateScope;\n start?: CreateTerminalRequest[\"start\"];\n title?: string;\n}\ninterface TerminalTargetArgs {\n terminalId: string;\n}\ninterface TerminalGetArgs extends TerminalTargetArgs {\n signal?: AbortSignal;\n}\ninterface TerminalRenameArgs extends TerminalTargetArgs {\n title: UpdateTerminalRequest[\"title\"];\n}\ninterface TerminalCloseArgs extends TerminalTargetArgs {\n mode: \"force\" | \"if-clean\";\n}\ninterface TerminalInputArgs extends TerminalTargetArgs {\n dataBase64: TerminalInputRequest[\"dataBase64\"];\n}\ninterface TerminalResizeArgs extends TerminalTargetArgs {\n cols: TerminalResizeRequest[\"cols\"];\n rows: TerminalResizeRequest[\"rows\"];\n}\ninterface TerminalOutputArgs extends TerminalTargetArgs {\n limitChunks?: TerminalOutputQuery[\"limitChunks\"];\n signal?: AbortSignal;\n sinceSeq?: TerminalOutputQuery[\"sinceSeq\"];\n tailBytes?: TerminalOutputQuery[\"tailBytes\"];\n}\ntype TerminalRestartArgs = TerminalTargetArgs;\ntype TerminalListResult = TerminalListResponse;\ntype TerminalCreateResult = TerminalSession;\ntype TerminalGetResult = TerminalSession;\ntype TerminalRenameResult = TerminalSession;\ntype TerminalCloseResult = TerminalSession;\ntype TerminalInputResult = TerminalSession;\ntype TerminalResizeResult = TerminalSession;\ntype TerminalOutputResult = TerminalOutputResponse;\ntype TerminalRestartResult = TerminalSession;\ninterface TerminalsArea {\n close(args: TerminalCloseArgs): Promise;\n create(args: TerminalCreateArgs): Promise;\n get(args: TerminalGetArgs): Promise;\n input(args: TerminalInputArgs): Promise;\n list(args: TerminalListArgs): Promise;\n output(args: TerminalOutputArgs): Promise;\n rename(args: TerminalRenameArgs): Promise;\n /**\n * Replace a terminal with a shell at the same scope, size, and title.\n * The original command is not replayed because terminal sessions do not\n * persist launch commands. The replacement has a new terminal ID.\n */\n restart(args: TerminalRestartArgs): Promise;\n resize(args: TerminalResizeArgs): Promise;\n}\n\ninterface ThreadListArgs {\n archived?: boolean;\n excludeSideChats?: boolean;\n sectionId?: string;\n hasParent?: boolean;\n limit?: number;\n offset?: number;\n originKind?: ThreadListQuery[\"originKind\"];\n parentThreadId?: string;\n projectId?: string;\n signal?: AbortSignal;\n sourceThreadId?: string;\n unsectioned?: boolean;\n}\ninterface ThreadSearchArgs extends ThreadSearchQuery {\n signal?: AbortSignal;\n}\ninterface ThreadGetArgs {\n include?: ThreadGetQuery[\"include\"];\n signal?: AbortSignal;\n threadId: string;\n}\ntype ThreadGetResult = ThreadResponse | ThreadWithIncludesResponse;\ntype ThreadListResult = ThreadListResponse;\ntype ThreadSearchResult = ThreadSearchResponse;\ninterface ThreadOutputResponse {\n output: string | null;\n}\ntype ThreadMutationResult = ThreadResponse;\ntype ThreadSpawnResult = ThreadResponse;\ntype ThreadInteractionGetResult = PendingInteraction;\ntype ThreadInteractionListResult = ThreadPendingInteractionsResponse;\ntype ThreadInteractionResolveResult = PendingInteraction;\ntype ThreadInteractionRespondResult = PendingInteraction;\ntype ThreadInteractionCancelResult = PendingInteraction;\ntype ThreadEventsListResult = ThreadEventRow[];\ntype ThreadEventWaitResult = ThreadEventRow | null;\ntype ThreadTimelineResult = ThreadTimelineResponse;\ntype ThreadArchiveResult = ThreadArchiveAllResponse;\ntype ThreadOpenResult = ThreadOpenResponse;\ntype ThreadPaneActionResult = ThreadPaneActionResponse;\ntype ThreadDeleteResult = {\n ok: true;\n};\ntype ThreadSendResult = {\n ok: true;\n};\ntype ThreadStopResult = {\n ok: true;\n};\ntype ThreadUnarchiveResult = {\n ok: true;\n};\ntype ThreadArchiveAllResult = ThreadArchiveAllResponse;\ntype ThreadReadStateResult = ThreadResponse;\ntype ThreadPinOrderResult = ThreadListResponse;\ntype ThreadPromptHistoryResult = PromptHistoryResponse;\ntype ThreadQueuedMessagesResult = ThreadQueuedMessageListResponse;\ntype ThreadQueuedMessageCreateResult = ThreadQueuedMessage;\ntype ThreadQueuedMessageUpdateResult = ThreadQueuedMessage;\ntype ThreadQueuedMessageDeleteResult = {\n ok: true;\n};\ntype ThreadQueuedMessageReorderResult = ThreadQueuedMessageListResponse;\ntype ThreadQueuedMessageSendResult = SendQueuedMessageResponse;\ntype ThreadQueuedMessageGroupBoundaryResult = ThreadQueuedMessageListResponse;\ntype ThreadTabsResult = ThreadTabsResponse;\ntype ThreadTabsUpdateResult = ThreadTabsResponse;\ntype ThreadStorageFilesResult = ThreadStorageFileListResponse;\ntype ThreadStoragePathsResult = ThreadStoragePathListResponse;\ntype ThreadChildSummaryResult = ThreadChildSummaryResponse;\ntype ThreadDefaultExecutionOptionsResult = ResolvedThreadExecutionOptions | null;\ntype ThreadConversationOutlineResult = ThreadConversationOutlineResponse;\ntype ThreadTimelineTurnSummaryDetailsResult = TimelineTurnSummaryDetailsResponse;\ninterface ThreadSpawnBaseArgs extends Omit {\n childOrigin?: CreateThreadRequest[\"childOrigin\"];\n origin?: CreateThreadRequest[\"origin\"];\n originKind?: CreateThreadRequest[\"originKind\"];\n startedOnBehalfOf?: CreateThreadRequest[\"startedOnBehalfOf\"];\n}\ntype ThreadSpawnArgs = ThreadSpawnBaseArgs & ({\n input: CreateThreadRequest[\"input\"];\n prompt?: never;\n} | {\n input?: never;\n prompt: string;\n});\ninterface ThreadUpdateArgs extends UpdateThreadRequest {\n threadId: string;\n}\ninterface ThreadDeleteArgs extends DeleteThreadRequest {\n threadId: string;\n}\ninterface ThreadSendArgs extends SendMessageRequest {\n threadId: string;\n}\ninterface ThreadActionArgs {\n threadId: string;\n}\ninterface ThreadStatusArgs extends ThreadActionArgs {\n signal?: AbortSignal;\n}\ninterface ThreadPromptHistoryArgs extends PromptHistoryQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadPinOrderArgs extends ReorderPinnedThreadRequest {\n threadId: string;\n}\ninterface ThreadQueuedMessageArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadQueuedMessageCreateArgs extends CreateQueuedMessageRequest {\n threadId: string;\n}\ninterface ThreadQueuedMessageUpdateArgs extends ThreadQueuedMessageTargetArgs, UpdateQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageTargetArgs {\n queuedMessageId: string;\n threadId: string;\n}\ninterface ThreadQueuedMessageSendArgs extends ThreadQueuedMessageTargetArgs, SendQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageReorderArgs extends ThreadQueuedMessageTargetArgs, ReorderQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageGroupBoundaryArgs extends SetQueuedMessageGroupBoundaryRequest {\n threadId: string;\n}\ninterface ThreadStorageFilesArgs extends ThreadStorageFilesQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadStoragePathsArgs extends ThreadStoragePathsQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadTimelineTurnSummaryDetailsArgs extends TimelineTurnSummaryDetailsQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadTabsUpdateArgs extends UpdateThreadTabsRequest {\n threadId: string;\n}\ninterface ThreadOpenArgs {\n threadId: string;\n split?: ThreadOpenSplit;\n file: ThreadOpenFile | null;\n}\ninterface ThreadPaneActionArgs {\n action: ThreadPaneAction;\n threadId: string;\n}\ninterface ThreadEventsListArgs {\n afterSeq?: string;\n limit?: string;\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadEventWaitArgs {\n afterSeq?: string;\n signal?: AbortSignal;\n threadId: string;\n type: string;\n waitMs: string;\n}\ninterface ThreadTimelineArgs extends ThreadTimelineQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadOutputArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadInteractionListArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadInteractionTargetArgs {\n interactionId: string;\n threadId: string;\n}\ninterface ThreadInteractionGetArgs extends ThreadInteractionTargetArgs {\n signal?: AbortSignal;\n}\ninterface ThreadInteractionResolveArgs extends ThreadInteractionTargetArgs {\n resolution: PendingInteractionResolution;\n}\ninterface ThreadInteractionRespondArgs extends ThreadInteractionTargetArgs {\n value: JsonValue;\n}\ntype ThreadWaitTarget = {\n kind: \"status\";\n status: ThreadStatus;\n} | {\n kind: \"event\";\n eventType: string;\n};\ninterface ThreadWaitArgs {\n event?: string;\n pollIntervalMs?: number;\n signal?: AbortSignal;\n status?: ThreadStatus;\n threadId: string;\n timeoutMs?: number;\n}\ntype ThreadWaitResult = {\n event: NonNullable;\n matched: true;\n target: Extract;\n threadId: string;\n} | {\n matched: true;\n target: Extract;\n thread: ThreadGetResult;\n threadId: string;\n};\ninterface ThreadInteractionsArea {\n cancel(args: ThreadInteractionTargetArgs): Promise;\n get(args: ThreadInteractionGetArgs): Promise;\n list(args: ThreadInteractionListArgs): Promise;\n resolve(args: ThreadInteractionResolveArgs): Promise;\n respond(args: ThreadInteractionRespondArgs): Promise;\n}\ninterface ThreadEventsArea {\n list(args: ThreadEventsListArgs): Promise;\n wait(args: ThreadEventWaitArgs): Promise;\n}\ninterface ThreadQueuedMessagesArea {\n create(args: ThreadQueuedMessageCreateArgs): Promise;\n delete(args: ThreadQueuedMessageTargetArgs): Promise;\n list(args: ThreadQueuedMessageArgs): Promise;\n reorder(args: ThreadQueuedMessageReorderArgs): Promise;\n send(args: ThreadQueuedMessageSendArgs): Promise;\n setGroupBoundary(args: ThreadQueuedMessageGroupBoundaryArgs): Promise;\n update(args: ThreadQueuedMessageUpdateArgs): Promise;\n}\ninterface ThreadTabsArea {\n get(args: ThreadStatusArgs): Promise;\n update(args: ThreadTabsUpdateArgs): Promise;\n}\ninterface ThreadsArea {\n archive(args: ThreadActionArgs): Promise;\n archiveAll(args: ThreadActionArgs): Promise;\n childSummary(args: ThreadStatusArgs): Promise;\n conversationOutline(args: ThreadStatusArgs): Promise;\n defaultExecutionOptions(args: ThreadStatusArgs): Promise;\n delete(args: ThreadDeleteArgs): Promise;\n events: ThreadEventsArea;\n get(args: ThreadGetArgs): Promise;\n interactions: ThreadInteractionsArea;\n list(args?: ThreadListArgs): Promise;\n markRead(args: ThreadActionArgs): Promise;\n markUnread(args: ThreadActionArgs): Promise;\n open(args: ThreadOpenArgs): Promise;\n paneAction(args: ThreadPaneActionArgs): Promise;\n output(args: ThreadOutputArgs): Promise;\n pin(args: ThreadActionArgs): Promise;\n promptHistory(args: ThreadPromptHistoryArgs): Promise;\n queuedMessages: ThreadQueuedMessagesArea;\n reorderPinned(args: ThreadPinOrderArgs): Promise;\n search(args: ThreadSearchArgs): Promise;\n send(args: ThreadSendArgs): Promise;\n spawn(args: ThreadSpawnArgs): Promise;\n stop(args: ThreadActionArgs): Promise;\n tabs: ThreadTabsArea;\n timeline(args: ThreadTimelineArgs): Promise;\n timelineTurnSummaryDetails(args: ThreadTimelineTurnSummaryDetailsArgs): Promise;\n storageFiles(args: ThreadStorageFilesArgs): Promise;\n storagePaths(args: ThreadStoragePathsArgs): Promise;\n unarchive(args: ThreadActionArgs): Promise;\n unpin(args: ThreadActionArgs): Promise;\n update(args: ThreadUpdateArgs): Promise;\n wait(args: ThreadWaitArgs): Promise;\n}\n\ntype ThreadSectionCreateResult = ThreadSectionResponse;\ntype ThreadSectionUpdateResult = ThreadSectionMutationResponse;\ntype ThreadSectionDeleteResult = ThreadSectionMutationResponse;\ntype ThreadSectionListResult = ThreadSectionResponse[];\ninterface ThreadSectionListArgs {\n signal?: AbortSignal;\n}\ninterface ThreadSectionsArea {\n create(args: CreateThreadSectionRequest): Promise;\n delete(args: DeleteThreadSectionRequest): Promise;\n list(args?: ThreadSectionListArgs): Promise;\n update(args: UpdateThreadSectionRequest): Promise;\n}\n\ninterface BbSdk extends BbRealtime {\n environments: EnvironmentsArea;\n files: FilesArea;\n guide: GuideArea;\n hosts: HostsArea;\n projects: ProjectsArea;\n plugins: PluginsArea;\n providers: ProvidersArea;\n status: StatusArea;\n system: SystemArea;\n terminals: TerminalsArea;\n theme: ThemeArea;\n threadSections: ThreadSectionsArea;\n threads: ThreadsArea;\n}\n\n/**\n * The backend plugin API contract — the `bb` object handed to a plugin's\n * `server.ts` factory (`export default function plugin(bb: BbPluginApi)`).\n *\n * Types only: the implementation lives in the BB server\n * (apps/server/src/services/plugins/plugin-api.ts), which imports these\n * shapes so the contract and the implementation cannot drift. Plugin authors\n * import them type-only (`import type { BbPluginApi } from\n * \"@bb/plugin-sdk\"`); the import is erased when BB loads the file.\n *\n * Runtime classes stay host-side. NeedsConfigurationError in particular is\n * matched by NAME, so plugin code needs no runtime import:\n * `throw Object.assign(new Error(msg), { name: \"NeedsConfigurationError\" })`.\n */\ninterface PluginLogger {\n debug(message: string): void;\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n/**\n * Declarative settings descriptors (`bb.settings.define`). Deliberately plain\n * data — not zod — so the host can render settings forms and the CLI can\n * parse values without executing plugin code.\n */\ntype PluginSettingDescriptor = {\n type: \"string\";\n label: string;\n description?: string;\n /** Stored in a 0600 file under /plugins//secrets/, never in the db or sent to the frontend. */\n secret?: true;\n default?: string;\n} | {\n type: \"boolean\";\n label: string;\n description?: string;\n default?: boolean;\n} | {\n type: \"select\";\n label: string;\n description?: string;\n options: string[];\n default?: string;\n} | {\n type: \"project\";\n label: string;\n description?: string;\n default?: string;\n};\ntype PluginSettingDescriptors = Record;\ntype PluginSettingValue = string | boolean;\n/** `default` present → non-optional value; absent → `T | undefined`. */\ntype PluginSettingsValues> = {\n [K in keyof Ds]: Ds[K] extends {\n default: string | boolean;\n } ? PluginSettingValueOf : PluginSettingValueOf | undefined;\n};\ntype PluginSettingValueOf = D extends {\n type: \"boolean\";\n} ? boolean : string;\ninterface PluginSettingsHandle> {\n /** Load-safe: callable inside the factory. */\n get(): Promise>;\n /** Fires after values change through the settings route/CLI. */\n onChange(listener: (next: PluginSettingsValues, prev: PluginSettingsValues) => void): void;\n}\ninterface PluginSettings {\n define>(descriptors: Ds): PluginSettingsHandle;\n}\ninterface PluginKvStorage {\n get(key: string): Promise;\n set(key: string, value: unknown): Promise;\n delete(key: string): Promise;\n list(prefix?: string): Promise;\n}\ninterface PluginStorage {\n /** Namespaced JSON key-value rows in bb.db; values ≤256KB each. */\n kv: PluginKvStorage;\n /**\n * Open (or reuse the path of) the plugin's own SQLite database at\n * /plugins//data.db — the server's better-sqlite3, WAL mode,\n * busy_timeout 5000. Handles are host-tracked and closed on\n * dispose/reload; a closed handle throws on use.\n */\n database(): Database.Database;\n /**\n * Ordered-statement migration helper: statement index = migration id in a\n * `_bb_migrations` table; unapplied statements run in one transaction.\n * Append-only — never reorder or edit shipped statements.\n */\n migrate(db: Database.Database, statements: string[]): void;\n}\n/**\n * Thread lifecycle events a plugin can observe (design §4.5). Observe-only:\n * handlers run fire-and-forget after the transition is applied and can never\n * block or veto it. `thread` is the same public DTO GET /threads/:id serves.\n */\ninterface PluginThreadEventPayloads {\n /** Fired after a thread row is created. */\n \"thread.created\": {\n thread: ThreadResponse;\n };\n /** Fired when a thread transitions into `active`. */\n \"thread.active\": {\n thread: ThreadResponse;\n };\n /** Fired when a thread transitions into `idle`. `lastAssistantText` is\n * assembled the same way GET /threads/:id/output is. */\n \"thread.idle\": {\n thread: ThreadResponse;\n lastAssistantText: string | null;\n };\n /** Fired when a thread transitions into `error`. `error` is the latest\n * system/error event message, when one exists. */\n \"thread.failed\": {\n thread: ThreadResponse;\n error: string | null;\n };\n /** Fired after a thread is soft-deleted. */\n \"thread.deleted\": {\n thread: ThreadResponse;\n };\n}\ntype PluginThreadEventName = keyof PluginThreadEventPayloads;\ntype PluginThreadEventHandler = (payload: PluginThreadEventPayloads[E]) => void | Promise;\ntype PluginHttpAuthMode = \"local\" | \"token\" | \"none\";\ntype PluginHttpHandler = (context: Context) => Response | Promise;\ninterface PluginHttp {\n /**\n * Register an HTTP route, mounted at\n * `/api/v1/plugins//http/`. Auth modes (default \"local\"):\n * - \"local\": Origin/Host must be a local BB app origin; non-GET requires\n * content-type application/json (forces a CORS preflight).\n * - \"token\": requires the per-plugin token (`bb plugin token `) via\n * the x-bb-plugin-token header or ?token=.\n * - \"none\": no checks — only for signature-verified webhooks.\n */\n route(method: string, path: string, handler: PluginHttpHandler, opts?: {\n auth?: PluginHttpAuthMode;\n }): void;\n}\ninterface PluginRpc {\n /**\n * Register a Standard Schema-driven rpc contract and its inferred handlers,\n * served at POST\n * `/api/v1/plugins//rpc/` with \"local\" auth semantics. The\n * host validates input before invocation and output before strict JSON\n * serialization. The response is `{ ok: true, result }` or\n * `{ ok: false, error: { code, message, issues? } }`.\n */\n register(contract: Contract, handlers: PluginRpcHandlers): void;\n}\ninterface PluginRealtime {\n /**\n * Broadcast an ephemeral `plugin-signal` WS message\n * `{ pluginId, channel, payload }` to every connected client (V1 has no\n * per-channel subscriptions). `payload` must be JSON-serializable;\n * `undefined` is normalized to `null`. Nothing is persisted.\n */\n publish(channel: string, payload: unknown): void;\n}\ninterface PluginBackground {\n /**\n * Register a long-lived background service. `start` runs after the\n * factory completes and should resolve when `signal` aborts\n * (dispose/reload/disable/shutdown). A crash restarts it with capped\n * exponential backoff; throwing NeedsConfigurationError marks the plugin\n * `needs-configuration` and stops restarting until the next load.\n */\n service(name: string, service: {\n start(signal: AbortSignal): void | Promise;\n }): void;\n /**\n * Register a cron schedule (5-field expression, server-local time). The\n * durable row keyed (pluginId, name) is upserted at load; the periodic\n * sweep claims due rows with a CAS on next_run_at, but only while this\n * plugin is loaded. Failures land in last_status/last_error, visible in\n * `bb plugin list`.\n */\n schedule(name: string, cron: string, fn: () => void | Promise): void;\n}\ninterface PluginCliCommandInfo {\n name: string;\n summary: string;\n usage: string;\n}\n/** Context forwarded from the invoking CLI when known; all fields optional. */\ninterface PluginCliContext {\n cwd?: string;\n threadId?: string;\n projectId?: string;\n /** Aborted when the invoking CLI HTTP request disconnects. */\n signal?: AbortSignal;\n}\ntype PluginInteractionCancelReason = \"user\" | \"request-aborted\" | \"thread-stopped\" | \"thread-deleted\" | \"plugin-disposed\" | \"server-restarted\" | \"timeout\";\ntype PluginInteractionResult = {\n outcome: \"submitted\";\n value: JsonValue$1;\n} | {\n outcome: \"cancelled\";\n reason: PluginInteractionCancelReason;\n};\ninterface PluginInteractionRequest {\n threadId: string;\n rendererId: string;\n title: string;\n payload: JsonValue$1;\n /** Defaults to ten minutes; capped at one hour. */\n timeoutMs?: number;\n}\ninterface PluginCliResult {\n exitCode: number;\n stdout?: string;\n stderr?: string;\n}\n/**\n * Maximum combined UTF-8 bytes accepted from plugin CLI stdout and stderr.\n * This is the shared source of truth for production and the testing harness.\n */\ndeclare const PLUGIN_CLI_OUTPUT_MAX_BYTES: number;\ninterface PluginCliOutputLimitError {\n code: \"plugin_cli_output_too_large\";\n message: string;\n maxBytes: number;\n stdoutBytes: number;\n stderrBytes: number;\n totalBytes: number;\n}\n/** Normalized host result returned by the plugin CLI HTTP/testing boundary. */\ninterface PluginCliExecutionResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n error?: PluginCliOutputLimitError;\n}\ninterface PluginCliRegistration {\n /** Top-level command name (`bb …`): lowercase [a-z0-9-]+, and not\n * a core bb command (see RESERVED_BB_CLI_COMMANDS in the server). */\n name: string;\n summary: string;\n /** Subcommand metadata rendered in help and the plugin-commands skill\n * without executing plugin code. Parsing argv is plugin-owned. */\n commands?: PluginCliCommandInfo[];\n run(argv: string[], ctx: PluginCliContext): PluginCliResult | Promise;\n}\ninterface PluginCli {\n /**\n * Register this plugin's `bb` subcommand. One registration per factory\n * execution; a repeated call is rejected. Core bb commands always win\n * name collisions; reserved names are rejected at registration.\n */\n register(registration: PluginCliRegistration): void;\n}\n/** Per-turn context handed to bb.agents context providers (design §4.4). */\n/** MCP-style content parts a native tool may return (design §4.4). */\ntype PluginAgentToolContentPart = {\n type: \"text\";\n text: string;\n} | {\n type: \"image\";\n data: string;\n mimeType: string;\n};\ntype PluginAgentToolResult = string | {\n content: PluginAgentToolContentPart[];\n isError?: boolean;\n};\n/** Per-call context handed to a native tool's execute (design §4.4). */\ninterface PluginAgentToolContext {\n threadId: string;\n projectId: string;\n /** The tool-call request's abort signal (aborts if the daemon round-trip\n * is torn down mid-call). */\n signal: AbortSignal;\n}\ninterface PluginAgentToolRegistrationBase {\n /** Tool name shown to the model: [a-zA-Z0-9_-]+, unique across plugins,\n * and not a built-in dynamic tool (see RESERVED_AGENT_TOOL_NAMES in the\n * server). */\n name: string;\n description: string;\n /**\n * Optional usage snippet appended to the thread instructions whenever\n * this tool is in the session's tool set (mirrors the built-in\n * update_environment_directory guidance). Limited to 4096 characters.\n */\n instructions?: string;\n}\n/** Stable, plain-data context resolved by the server for one agent session. */\ninterface PluginAgentConfigurationContext {\n thread: {\n id: string;\n title: string | null;\n parentThreadId: string | null;\n sourceThreadId: string | null;\n };\n project: {\n id: string;\n kind: \"standard\" | \"personal\";\n name: string;\n gitRemoteUrl: string | null;\n };\n environment: {\n id: string;\n name: string | null;\n path: string | null;\n workspaceProvisionType: \"unmanaged\" | \"managed-worktree\" | \"personal\";\n branchName: string | null;\n };\n host: {\n id: string;\n name: string;\n };\n provider: {\n id: string;\n model: string;\n };\n sideChat: boolean;\n origin: {\n kind: \"fork\" | \"side-chat\" | null;\n pluginId: string | null;\n };\n}\n/** Object form of a {@link PluginAgentConfiguration} tools entry: selects a\n * registered tool and overrides the parameter schema advertised to the\n * provider for this resolution only. */\ninterface PluginAgentToolSelection {\n /** Name of a tool registered by this plugin via `registerTool`. */\n name: string;\n /** JSON-schema object (root `type: \"object\"`, JSON-serializable, at most\n * 128 KiB serialized) sent to the provider in place of the registered\n * parameter schema. Execution-side validation still runs the registered\n * parameters, so the override must only narrow what the registered schema\n * already accepts. */\n parameters: Record;\n}\n/** Per-resolution selection returned by {@link PluginAgents.configure}. */\ninterface PluginAgentConfiguration {\n /** Tool names registered by this plugin, or {@link PluginAgentToolSelection}\n * entries to also override a tool's advertised parameter schema for this\n * resolution. Duplicate or unknown names, or an invalid override, reject\n * this plugin's complete selection for the resolution. */\n tools: Array;\n /** Skill frontmatter names from this plugin's manifest skill roots.\n * Duplicate or unknown names reject this plugin's complete selection. */\n skills: string[];\n /** Optional dynamic instructions. Output is truncated to 4096 characters. */\n instructions?: string;\n}\ninterface PluginAgents {\n /**\n * Select this plugin's statically registered tools and manifest skills for\n * each thread/session resolution, with optional dynamic instructions. The\n * callback is synchronous and runs at `thread.start` / `turn.submit`; it\n * never rebuilds registrations. Exactly one callback may be registered per\n * factory execution. A throw, malformed result, duplicate id, unknown id,\n * or more than 256 tool/skill ids fails closed for this plugin only.\n *\n * Tools take effect when the provider session is next started or resumed;\n * an already-running session is not hot-mutated. Instructions are resolved\n * for the next turn. Skill changes follow BB's environment runtime policy:\n * a busy runtime keeps its current catalog until a safe relaunch. Side-chat\n * threads receive `sideChat: true`, and their returned tool, skill, and\n * dynamic-instruction selections apply at the same boundaries. Independent\n * side-chat safety policy (such as permission escalation) is unchanged.\n */\n configure(provider: (context: PluginAgentConfigurationContext) => PluginAgentConfiguration): void;\n /**\n * Register a native dynamic tool (design §4.4). `parameters` is either a\n * zod schema (validated per call; execute receives the parsed value) or a\n * plain JSON-schema object (no validation; execute receives the raw\n * arguments as `unknown`). Tool-set changes apply on the NEXT session\n * start — a tool registered mid-session is not hot-added to running\n * provider sessions. A second registration of the same name within this\n * plugin is rejected; a name already registered by another plugin is\n * rejected and surfaced as this plugin's status detail.\n */\n registerTool(tool: PluginAgentToolRegistrationBase & {\n parameters: Schema;\n execute(params: z.output, ctx: PluginAgentToolContext): PluginAgentToolResult | Promise;\n }): void;\n registerTool(tool: PluginAgentToolRegistrationBase & {\n /** Raw JSON-schema escape hatch; params arrive unvalidated. */\n parameters: Record;\n execute(params: unknown, ctx: PluginAgentToolContext): PluginAgentToolResult | Promise;\n }): void;\n /**\n * Contribute a dynamic section appended to thread instructions. The\n * provider runs when a thread's runtime command config is resolved\n * (thread.start / turn.submit); return null to contribute nothing for\n * that resolution. Must be synchronous and fast — it sits on the\n * thread-start path. Output longer than 4096 characters is truncated; a\n * throwing provider is logged against the plugin and contributes nothing.\n * A repeated registration within one factory execution is rejected.\n * This legacy contribution is not applied to side-chat threads; use\n * configure() when sideChat-aware dynamic instructions are required.\n */\n contributeInstructions(provider: (ctx: {\n threadId: string;\n projectId: string;\n }) => string | null): void;\n}\ninterface PluginThreadActionContext {\n threadId: string;\n projectId: string;\n}\ninterface PluginThreadActionToast {\n kind: \"success\" | \"error\" | \"info\";\n message: string;\n}\ntype PluginThreadActionResult = void | {\n toast?: PluginThreadActionToast;\n};\ninterface PluginThreadActionRegistration {\n /** Unique within this plugin: [a-zA-Z0-9_-]+ (becomes a URL segment). */\n id: string;\n /** Button label rendered in the thread header. */\n title: string;\n /** Optional icon name; the host falls back to a generic icon. */\n icon?: string;\n /** Optional confirmation prompt the host shows before running. */\n confirm?: string;\n /**\n * Runs server-side when the user clicks the action. The host shows a\n * pending state while in flight, the returned toast on completion, and an\n * automatic error toast when this throws.\n */\n run(ctx: PluginThreadActionContext): PluginThreadActionResult | Promise;\n}\ntype PluginMentionTrigger = \"@\" | \"#\" | \"$\" | \"!\" | \"~\";\n/** Search context handed to a mention provider (design §4.9). `projectId`/\n * `threadId` are null when the composer has not committed one yet. */\ninterface PluginMentionSearchContext {\n trigger: PluginMentionTrigger;\n query: string;\n projectId: string | null;\n threadId: string | null;\n}\n/** One row a mention provider returns from `search`. `id` is the provider's\n * own item id — the host namespaces it before it reaches the wire. */\ninterface PluginMentionItem {\n id: string;\n title: string;\n subtitle?: string;\n icon?: string;\n}\ninterface PluginMentionProviderRegistration {\n /** Unique within this plugin: [a-zA-Z0-9_-]+ (no \":\" — the host composes\n * wire item ids as \":\"). */\n id: string;\n /** Section label shown above this provider's rows in the mention menu. */\n label: string;\n /**\n * Composer trigger characters this provider should answer. Omit to use the\n * default `@` mention trigger. Valid triggers are `@`, `#`, `$`, `!`, and `~`.\n */\n triggers?: readonly PluginMentionTrigger[];\n /**\n * Runs server-side as the user types after one of this provider's triggers\n * in the composer. Each call is time-boxed (2s) and failure-isolated: a slow\n * or throwing provider contributes an empty list — it can never break the\n * mention menu.\n */\n search(ctx: PluginMentionSearchContext): PluginMentionItem[] | Promise;\n /**\n * Resolves one picked item into agent context, called once per unique\n * item at message send time. The returned `context` is attached to the\n * message as an agent-visible (user-hidden) prompt input. Throwing blocks\n * the send with a visible error.\n */\n resolve(itemId: string): {\n context: string;\n } | Promise<{\n context: string;\n }>;\n}\ninterface PluginUi {\n /** Block until the app submits or cancels a plugin-owned composer form. */\n requestInput(request: PluginInteractionRequest, options?: {\n signal?: AbortSignal;\n }): Promise;\n /**\n * Register a thread action rendered in the shipped app's thread header\n * (design §4.9). Multiple actions per plugin; ids must be unique within\n * the plugin. Invoked via POST /plugins/:id/actions/:actionId.\n */\n registerThreadAction(action: PluginThreadActionRegistration): void;\n /**\n * Register a mention provider for the shipped app's composer (design §4.9).\n * Providers default to the `@` trigger and may opt into `#`, `$`, `!`, or\n * `~` with `triggers`. Items group under `label` in the mention menu; a\n * picked item becomes a `{ kind: \"plugin\" }` mention resource whose context\n * is resolved once at send time. Multiple providers per plugin; ids must be\n * unique within the plugin.\n */\n registerMentionProvider(provider: PluginMentionProviderRegistration): void;\n}\ninterface PluginEvents {\n /**\n * Add a thread lifecycle listener. Multiple listeners for the same event are\n * additive and run independently in registration order.\n */\n on(event: E, handler: PluginThreadEventHandler): void;\n}\ninterface PluginServerApi {\n /**\n * This BB server's own loopback base URL (e.g. \"http://127.0.0.1:38886\"),\n * which serves the SPA + /api + /ws. For plugins that proxy or relay\n * traffic back to the server itself (e.g. a tunnel). Bind-gated like\n * `bb.sdk`: reading it before the server is listening throws, so prefer\n * reading it from handlers, services, and timers.\n */\n readonly loopbackBaseUrl: string;\n}\ninterface PluginSharedPortTunnelIdentity {\n /** Gate routing label assigned to this machine. */\n label: string;\n /** Gate apex without a scheme, e.g. \"getbb.app\". */\n baseDomain: string;\n}\ninterface PluginHosts {\n /**\n * Ensure this enrolled host has a gate label and return its read-only public\n * identity. The daemon chooses the trusted gate and desired label; plugins\n * cannot influence either credential-bearing destination.\n */\n ensureSharedPortTunnel(hostId: string): Promise;\n /**\n * Replace this plugin's desired shared-loopback ports for one host. The\n * server aggregates declarations, owns generations, and delivers the\n * resulting set to that host's daemon. Tunnel identity is deliberately not\n * accepted here: it is owned by the daemon's trusted enrollment.\n */\n declareSharedPorts(hostId: string, ports: readonly number[]): void;\n}\ninterface PluginStatusApi {\n /**\n * Mark this plugin `needs-configuration` (with a message shown in\n * `bb plugin list` and the UI) instead of failing — e.g. a factory or\n * service that finds no API key configured. Cleared on the next load;\n * saving settings does not auto-reload in V1, so ask the user to\n * `bb plugin reload ` after configuring.\n */\n needsConfiguration(message: string): void;\n}\n/**\n * The API object handed to a plugin's factory (design §4). Implemented by\n * the BB server; this contract is what plugin `server.ts` files compile\n * against.\n */\ninterface BbPluginApi {\n /** The plugin's own id (namespaces storage, routes, commands). */\n readonly pluginId: string;\n /** Leveled, plugin-scoped logger. */\n readonly log: PluginLogger;\n /** Declarative settings (design §4.2). */\n readonly settings: PluginSettings;\n /** Namespaced KV + per-plugin database (design §4.3). */\n readonly storage: PluginStorage;\n /** HTTP routes under /api/v1/plugins//http/* (design §4.6). */\n readonly http: PluginHttp;\n /** RPC methods under /api/v1/plugins//rpc/ (design §4.6). */\n readonly rpc: PluginRpc;\n /** Ephemeral push to connected frontends (design §4.7). */\n readonly realtime: PluginRealtime;\n /** Long-lived services + cron schedules (design §4.8). */\n readonly background: PluginBackground;\n /** Agent-facing `bb` CLI subcommand (design §4.4). */\n readonly cli: PluginCli;\n /** Per-turn agent context contributions (design §4.4). */\n readonly agents: PluginAgents;\n /** Host-rendered UI contributions (design §4.9). */\n readonly ui: PluginUi;\n /** Additive plugin lifecycle listeners (design §4.5). */\n readonly events: PluginEvents;\n /** Plugin-reported status (needs-configuration). */\n readonly status: PluginStatusApi;\n /** Read-only facts about the running server (loopback base URL). */\n readonly server: PluginServerApi;\n /** Server-to-daemon host control-plane declarations. */\n readonly hosts: PluginHosts;\n /**\n * The full BB SDK, bound to this server over loopback (design §4.1).\n * Bind-gated: reading this before the host binds the SDK throws. The real\n * server binds it before loading plugins, so it is available from the\n * moment factories run there — but isolated harnesses may not, so prefer\n * using it from handlers, services, and timers for portability.\n * `threads.spawn` defaults `origin` to \"plugin\" and `originPluginId` to\n * this plugin's id so spawned threads are attributed automatically.\n */\n readonly sdk: BbSdk;\n /**\n * Register cleanup to run on reload/disable/shutdown. Hooks run LIFO.\n * The sanctioned place to clear timers and close connections.\n */\n onDispose(hook: () => void | Promise): void;\n}\n\nexport { PLUGIN_CLI_OUTPUT_MAX_BYTES, defineRpcContract };\nexport type { BbContext, BbNavigate, BbPluginApi, JsonValue$1 as JsonValue, PluginAgentConfiguration, PluginAgentConfigurationContext, PluginAgentToolContentPart, PluginAgentToolContext, PluginAgentToolRegistrationBase, PluginAgentToolResult, PluginAgentToolSelection, PluginAgents, PluginAppBuilder, PluginAppDefinition, PluginAppSetup, PluginAppSlots, PluginBackground, PluginCli, PluginCliCommandInfo, PluginCliContext, PluginCliExecutionResult, PluginCliOutputLimitError, PluginCliRegistration, PluginCliResult, PluginComposerAccessoryProps, PluginComposerAccessoryRegistration, PluginComposerApi, PluginComposerMention, PluginComposerScope, PluginEvents, PluginFileOpenerProps, PluginFileOpenerRegistration, PluginFileOpenerSource, PluginHomepageSectionProps, PluginHomepageSectionRegistration, PluginHosts, PluginHttp, PluginHttpAuthMode, PluginHttpHandler, PluginInteractionCancelReason, PluginInteractionRequest, PluginInteractionResult, PluginKvStorage, PluginLogger, PluginMentionItem, PluginMentionProviderRegistration, PluginMentionSearchContext, PluginMentionTrigger, PluginMessageDirectiveMessage, PluginMessageDirectiveOpenThreadPanel, PluginMessageDirectiveOpenWorkspaceFile, PluginMessageDirectiveProps, PluginMessageDirectiveRegistration, PluginMessageDirectiveThreadPanelOptions, 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 };\n"; +export const PLUGIN_SDK_DTS = "// Portable type declarations for `@bb/plugin-sdk`. Unpublished BB\n// workspace contracts are flattened; public subpaths may reuse the\n// package root without requiring any other @bb/* package.\n//\n// Confused by the API, or need a symbol that isn't here? Clone the BB repo\n// and read the real source: https://github.com/ymichael/bb\n\nimport { ComponentType } from 'react';\nimport Database from 'better-sqlite3';\nimport { Context } from 'hono';\nimport * as z from 'zod';\nimport { z as z$1 } from 'zod';\n\n/**\n * A value that survives a JSON round trip without coercion or data loss.\n *\n * Host boundaries still validate values at runtime because TypeScript cannot\n * exclude non-finite numbers and plugin bundles can bypass static types.\n */\ntype JsonValue$1 = string | number | boolean | null | JsonValue$1[] | {\n [key: string]: JsonValue$1;\n};\n\n/** A JSON-safe path segment reported by a Standard Schema validation issue. */\ntype PluginRpcIssuePathSegment = string | number;\n/** Validator-neutral validation detail carried by an RPC error envelope. */\ninterface PluginRpcValidationIssue {\n message: string;\n path?: PluginRpcIssuePathSegment[];\n}\n/** Stable wire error categories for plugin RPC. */\ntype PluginRpcErrorCode = \"invalid_json\" | \"invalid_input\" | \"handler_error\" | \"invalid_output\" | \"non_json_result\" | \"unknown_method\";\n/** Structured RPC failure returned as `{ ok: false, error }`. */\ninterface PluginRpcError {\n code: PluginRpcErrorCode;\n message: string;\n issues?: PluginRpcValidationIssue[];\n}\n/**\n * The validator-neutral subset of Standard Schema v1 used by plugin RPC.\n * Zod 4 schemas implement this interface directly; other validators can do\n * the same without becoming part of BB's public protocol.\n */\ninterface StandardSchemaV1 {\n readonly \"~standard\": {\n readonly version: 1;\n readonly vendor: string;\n readonly validate: (value: unknown) => StandardSchemaV1Result | Promise>;\n readonly types?: {\n readonly input: Input;\n readonly output: Output;\n };\n };\n}\ntype StandardSchemaV1Result = {\n readonly value: Output;\n readonly issues?: undefined;\n} | {\n readonly issues: readonly StandardSchemaV1Issue[];\n};\ninterface StandardSchemaV1Issue {\n readonly message: string;\n readonly path?: PropertyKey | readonly (PropertyKey | {\n readonly key: PropertyKey;\n })[];\n}\ntype StandardSchemaV1InferInput = NonNullable[\"input\"];\ntype StandardSchemaV1InferOutput = NonNullable[\"output\"];\ninterface PluginRpcMethodContract {\n readonly input: InputSchema;\n readonly output: OutputSchema;\n}\ntype PluginRpcContract = Readonly>;\n/** Define a shared RPC contract while preserving exact method/schema types. */\ndeclare function defineRpcContract(contract: Contract): Contract;\ntype PluginRpcHandlers = {\n [Method in keyof Contract]: (input: StandardSchemaV1InferOutput) => StandardSchemaV1InferInput | Promise>;\n};\ntype PluginRpcCallInput = StandardSchemaV1InferInput;\ntype PluginRpcCallArgs = null extends PluginRpcCallInput ? [input?: PluginRpcCallInput] : [input: PluginRpcCallInput];\ntype PluginRpcResult = StandardSchemaV1InferOutput;\n\n/**\n * The `@bb/plugin-sdk/app` contract (plugin design §5.2) — pure types with no\n * side effects. The BB app imports these to keep its real implementation in\n * sync (`satisfies PluginSdkApp`). Plugin authors import the same shapes through\n * `@bb/plugin-sdk/app`.\n *\n * Per-slot props are versioned contracts: additive-only within an SDK major.\n */\n/** Props passed to a `homepageSection` component. */\ninterface PluginHomepageSectionProps {\n /** Project in view on the compose surface; null when none is selected. */\n projectId: string | null;\n}\n/**\n * Props passed to a `settingsSection` component.\n *\n * Deliberately empty in V1; versioned additive like the other slot props.\n */\ninterface PluginSettingsSectionProps {\n}\n/** Props passed to a `navPanel` component (it owns its whole route). */\ninterface PluginNavPanelProps {\n /**\n * The route remainder after the panel root, \"\" at the root. The panel's\n * route is `/plugins///*`, so a deep link like\n * `/plugins/notes/notes/work/ideas.md` renders the panel with\n * `subPath: \"work/ideas.md\"`. Navigate within the panel via\n * `useBbNavigate().toPluginPanel(path, { subPath })` — browser\n * back/forward then walks panel-internal history.\n */\n subPath: string;\n}\n/** Props passed to a panel tab opened by a `threadPanelAction`. */\ninterface PluginThreadPanelProps {\n threadId: string;\n /**\n * The JSON value the action's `openPanel` call passed (round-tripped\n * through persistence, so the tab restores across reloads); null when the\n * action opened the panel without params.\n */\n params: JsonValue$1 | null;\n}\n/** Props passed to a `composerAccessory` component. */\ninterface PluginComposerAccessoryProps {\n projectId: string | null;\n threadId: string | null;\n}\ninterface PluginPendingInteractionView {\n id: string;\n threadId: string;\n title: string;\n payload: JsonValue$1;\n createdAt: number;\n expiresAt: number | null;\n}\ninterface PluginPendingInteractionProps {\n interaction: PluginPendingInteractionView;\n submit(value: JsonValue$1): Promise;\n cancel(): Promise;\n}\n/**\n * Props for a `sidebarFooterAction` — host-rendered (no plugin component).\n * Deliberately empty; the registration's `run` carries the behavior.\n */\ninterface PluginSidebarFooterActionProps {\n}\n/**\n * Where a file being opened by a `fileOpener` lives. `path` semantics follow\n * the source: workspace paths are relative to the environment's worktree,\n * thread-storage paths are relative to the thread's storage root, host paths\n * are absolute on the thread's host.\n */\ninterface PluginFileOpenerSource {\n kind: \"workspace\" | \"host\" | \"thread-storage\";\n threadId: string | null;\n environmentId: string | null;\n projectId: string | null;\n}\n/** Props passed to a `fileOpener` component (rendered as a panel file tab). */\ninterface PluginFileOpenerProps {\n path: string;\n source: PluginFileOpenerSource;\n}\n/**\n * Message context passed to a `messageDirective` component — the assistant\n * (or nested agent) message that contained the directive.\n */\ninterface PluginMessageDirectiveMessage {\n id: string;\n threadId: string;\n turnId: string | null;\n projectId: string | null;\n}\n/**\n * Open a worktree-relative file in the host's workspace file viewer. Returns\n * true when the host accepted the path; false when the path is invalid or the\n * viewer declined it.\n */\ntype PluginMessageDirectiveOpenWorkspaceFile = (path: string) => boolean;\ninterface PluginMessageDirectiveThreadPanelOptions {\n /** A `threadPanelAction` id registered by this same plugin. */\n actionId: string;\n title?: string;\n params?: JsonValue$1;\n}\n/** Open this plugin's registered action in the current thread side panel. */\ntype PluginMessageDirectiveOpenThreadPanel = (options: PluginMessageDirectiveThreadPanelOptions) => boolean;\n/**\n * Props passed to a `messageDirective` component. Attributes are untrusted\n * strings parsed from the directive; the plugin validates its own fields.\n */\ninterface PluginMessageDirectiveProps {\n /** Parsed, untrusted directive attributes (e.g. `{ file: \"demo.html\" }`). */\n attributes: Readonly>;\n /** Original directive source text (useful for diagnostics / crash fallback). */\n source: string;\n message: PluginMessageDirectiveMessage;\n /**\n * Opens a worktree-relative file in the host's workspace file viewer. Null\n * when the message surface has no workspace viewer available.\n */\n openWorkspaceFile: PluginMessageDirectiveOpenWorkspaceFile | null;\n /**\n * Opens one of this plugin's own `threadPanelAction` components in the\n * current thread side panel. Omitted by older hosts; null on message\n * surfaces without a thread panel.\n */\n openThreadPanel?: PluginMessageDirectiveOpenThreadPanel | null;\n}\ninterface PluginHomepageSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n component: ComponentType;\n}\ninterface PluginSettingsSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Optional host-rendered section heading. */\n title?: string;\n /**\n * Optional one-line host-rendered subheading under `title`, in the built-in\n * SettingsSection idiom (ignored when `title` is absent).\n */\n description?: string;\n component: ComponentType;\n}\ninterface PluginNavPanelRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /** URL segment under `/plugins//`; letters, digits, `-`, `_`. */\n path: string;\n component: ComponentType;\n /**\n * Optional component rendered on the right side of the shared title bar\n * (e.g. a sync button or a count). Contained separately from the body: a\n * throwing headerContent is hidden without breaking the title bar.\n */\n headerContent?: ComponentType;\n}\n/** Context handed to a `threadPanelAction`'s `run`. */\ninterface PluginThreadPanelActionContext {\n /** The thread whose panel launcher invoked the action. */\n threadId: string;\n /**\n * Open a tab in the thread's side panel rendering this action's\n * `component`. `title` labels the tab (default: the action's `title`);\n * `params` must be JSON-serializable — it is persisted with the tab and\n * reaches the component as its `params` prop. Opening with params\n * identical to an already-open tab of this action focuses that tab\n * (updating its title) instead of duplicating it. May be called more than\n * once (different params ⇒ multiple tabs) or not at all.\n */\n openPanel(options?: {\n title?: string;\n params?: JsonValue$1;\n }): void;\n}\ninterface PluginThreadPanelActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label of the action row in the panel's new-tab launcher. */\n title: string;\n /**\n * Icon hint (BB icon name) used when the plugin ships no logo; the\n * launcher row and opened tabs prefer the plugin's logo.\n */\n icon?: string;\n /** Rendered inside every panel tab this action opens. */\n component: ComponentType;\n /**\n * Runs when the user activates the action: call your RPC methods, show a\n * toast, and/or open panel tabs via `context.openPanel`. Omitted =\n * immediately open a panel tab with defaults. Errors (sync or async) are\n * contained and logged; they never break the launcher.\n */\n run?(context: PluginThreadPanelActionContext): void | Promise;\n}\ninterface PluginComposerAccessoryRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n component: ComponentType;\n}\ninterface PluginPendingInteractionRegistration {\n /** Matches `rendererId` passed to `bb.ui.requestInput`. */\n id: string;\n component: ComponentType;\n}\n/** Context handed to a `sidebarFooterAction`'s `run`. */\ninterface PluginSidebarFooterActionContext {\n /**\n * Navigate to this plugin's Settings detail page\n * (`/settings/plugins/`), where declarative settings and\n * `settingsSection` slots render.\n */\n openSettings(): void;\n}\n/**\n * An icon button in the app sidebar footer (next to Settings / bug report).\n * Host-rendered for consistent chrome — plugins supply icon, label, and\n * `run` behavior only.\n */\ninterface PluginSidebarFooterActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Tooltip and accessible label for the icon button. */\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /**\n * Runs when the user activates the action (e.g. call `openSettings()`,\n * open a panel via other surfaces, toast). Errors (sync or async) are\n * contained and logged; they never break the sidebar.\n */\n run(context: PluginSidebarFooterActionContext): void | Promise;\n}\n/**\n * Register this plugin as a viewer/editor for file extensions. The user\n * picks (and can set as default) an opener per extension via the file tab's\n * \"Open with\" menu; matching files opened in the panel then render\n * `component` in a plugin tab instead of the built-in preview. Applies to\n * working-tree, host, and thread-storage files — never to git-ref snapshots\n * (diff views always use the built-in preview). The built-in preview stays\n * one menu click away, and a missing/disabled opener falls back to it.\n */\ninterface PluginFileOpenerRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label in the \"Open with\" menu (e.g. \"Notes editor\"). */\n title: string;\n /** Lowercase extensions without the dot (e.g. [\"md\", \"mdx\"]). */\n extensions: readonly string[];\n component: ComponentType;\n}\n/**\n * Register a leaf message directive rendered inside assistant (and nested\n * agent) message Markdown. `id` is the directive name: `inline-vis` matches\n * `::inline-vis{file=\"demo.html\"}`.\n */\ninterface PluginMessageDirectiveRegistration {\n /**\n * The directive name. Lowercase kebab-case beginning with a letter.\n */\n id: string;\n component: ComponentType;\n}\ninterface PluginAppSlots {\n homepageSection(registration: PluginHomepageSectionRegistration): void;\n settingsSection(registration: PluginSettingsSectionRegistration): void;\n navPanel(registration: PluginNavPanelRegistration): void;\n threadPanelAction(registration: PluginThreadPanelActionRegistration): void;\n composerAccessory(registration: PluginComposerAccessoryRegistration): void;\n pendingInteraction(registration: PluginPendingInteractionRegistration): void;\n sidebarFooterAction(registration: PluginSidebarFooterActionRegistration): void;\n fileOpener(registration: PluginFileOpenerRegistration): void;\n messageDirective(registration: PluginMessageDirectiveRegistration): void;\n}\ninterface PluginAppBuilder {\n slots: PluginAppSlots;\n}\ntype PluginAppSetup = (app: PluginAppBuilder) => void;\n/**\n * The opaque product of `definePluginApp` — a plugin's `app.tsx` default\n * export. The host re-runs `setup` against a fresh collector on every\n * (re)interpretation, replacing that plugin's registrations wholesale.\n */\ninterface PluginAppDefinition {\n /** Brand the host checks before interpreting a bundle's default export. */\n readonly __bbPluginApp: true;\n readonly setup: PluginAppSetup;\n}\ninterface PluginRpcClient {\n /**\n * Invoke one of the plugin's `bb.rpc` methods (POST\n * /api/v1/plugins/<id>/rpc/<method>). Resolves with the method's\n * inferred output; rejects with an `Error` carrying the server's message,\n * stable `code`, and validation `issues` when present.\n */\n call>(method: Method, ...args: PluginRpcCallArgs): Promise>;\n}\ninterface PluginSettingsState {\n /**\n * Effective non-secret setting values (secret settings are excluded —\n * read them server-side). Undefined while loading or unavailable.\n */\n values: Record | undefined;\n isLoading: boolean;\n}\n/** State of the app's shared realtime connection to the bb server. */\ntype PluginRealtimeConnectionState = \"connecting\" | \"connected\" | \"reconnecting\";\n/** Where `useComposer()` writes: the active thread's draft or the new-thread draft. */\ntype PluginComposerScope = {\n kind: \"thread\";\n threadId: string;\n} | {\n kind: \"new-thread\";\n projectId: string | null;\n};\n/** An @-mention pill bound to one of the calling plugin's mention providers. */\ninterface PluginComposerMention {\n /** Mention provider id registered by THIS plugin via `bb.ui.registerMentionProvider`. */\n provider: string;\n /** Item id your provider's `resolve` will receive at send time. */\n id: string;\n /** Pill text shown in the composer. */\n label: string;\n}\n/**\n * Programmatic access to the chat composer draft — the same shared draft the\n * built-in \"Add to chat\" affordances (file preview, diff, terminal selections)\n * write to. Inside a thread context writes land in that thread's draft;\n * anywhere else (nav panel, homepage section) they seed the new-thread\n * composer draft, which persists until the user sends or clears it.\n */\ninterface PluginComposerApi {\n scope: PluginComposerScope;\n /** Current plain text for this composer scope. */\n readonly text: string;\n /**\n * Replace the draft's plain text. Attachments are preserved. Inline mentions\n * outside the changed range are preserved and rebased; mentions overlapped\n * by the replacement are removed because their text representation changed.\n */\n setText(next: string): void;\n /**\n * Replace the draft's plain text from the latest committed value. Uses the\n * same structured-state reconciliation as `setText`.\n */\n updateText(updater: (current: string) => string): void;\n /** Clear plain text without clearing independently attached files. */\n clear(): void;\n /**\n * Append text to the draft as a `> ` blockquote block and focus the\n * composer. Blank text is a no-op. This is the \"reference this selection\n * in chat\" primitive.\n */\n addQuote(text: string): void;\n /**\n * Insert an @-mention pill that resolves through this plugin's mention\n * provider at send time — the durable way to reference an entity whose\n * content should be fetched fresh when the message is sent.\n */\n insertMention(mention: PluginComposerMention): void;\n /** Focus the composer caret at the end of the draft. */\n focus(): void;\n}\n/** Current app selection, derived from the route. */\ninterface BbContext {\n projectId: string | null;\n threadId: string | null;\n}\ninterface BbNavigate {\n toThread(threadId: string): void;\n toProject(projectId: string): void;\n /**\n * Navigate to one of this plugin's own nav panels by its `path`.\n * `subPath` targets a location inside the panel (the component's\n * `subPath` prop); `replace` swaps the current history entry instead of\n * pushing — use it for redirects so back does not bounce.\n */\n toPluginPanel(path: string, options?: {\n subPath?: string;\n replace?: boolean;\n }): void;\n /**\n * Navigate to the root compose surface (the new-thread screen). Pass\n * `initialPrompt` to seed the composer draft and `focusPrompt` to focus the\n * composer on arrival — the pairing behind \"Create via chat\" style entry\n * points that drop the user into chat with a prefilled prompt.\n */\n toCompose(options?: {\n initialPrompt?: string;\n focusPrompt?: boolean;\n }): void;\n}\n/**\n * Everything `@bb/plugin-sdk/app` resolves to at runtime. The BB app builds\n * the real implementation and `satisfies` this interface; `bb plugin build`\n * shims the specifier to that object on `globalThis.__bbPluginRuntime`.\n */\ninterface PluginSdkApp {\n definePluginApp(setup: PluginAppSetup): PluginAppDefinition;\n useRpc(): PluginRpcClient;\n useRealtime(channel: string, handler: (payload: unknown) => void): void;\n /**\n * Observe the same shared connection that delivers `useRealtime` signals.\n * Use a subsequent transition to `connected` to reconcile server state that\n * may have changed while ephemeral signals could not be delivered. The first\n * connection can transition from `connecting` and is not a reconnection.\n */\n useRealtimeConnectionState(): PluginRealtimeConnectionState;\n useSettings(): PluginSettingsState;\n useBbContext(): BbContext;\n useBbNavigate(): BbNavigate;\n useComposer(): PluginComposerApi;\n}\n\n/**\n * App-wide server-backed preferences.\n * Client-local settings stay in the frontend localStorage helpers instead.\n */\ndeclare const appSettingsSchema: z$1.ZodObject<{\n caffeinate: z$1.ZodBoolean;\n showKeyboardHints: z$1.ZodBoolean;\n showUnhandledProviderEvents: z$1.ZodBoolean;\n codexMemoryEnabled: z$1.ZodBoolean;\n claudeCodeMemoryEnabled: z$1.ZodBoolean;\n codexSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeWorkflowsDisabled: z$1.ZodBoolean;\n}, z$1.core.$strict>;\ntype AppSettings = z$1.infer;\n\ndeclare const appKeybindingOverridesSchema: z$1.ZodArray;\n shortcut: z$1.ZodNullable>;\n}, z$1.core.$strict>>;\ntype AppKeybindingOverrides = z$1.infer;\n\ndeclare const appThemeSchema: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n}, z$1.core.$strip>;\ntype AppTheme = z$1.infer;\n/**\n * The complete appearance selection a client sends when changing the palette\n * and/or favicon tint. The server validates `themeId` (built-in id or an\n * existing custom theme) and resolves the CSS from disk for custom themes.\n * Callers changing only one facet must carry the other facet forward explicitly.\n */\ndeclare const appThemeSelectionSchema: z$1.ZodObject<{\n themeId: z$1.ZodString;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n}, z$1.core.$strip>;\ntype AppThemeSelection = z$1.infer;\n\ndeclare const changedMessageSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"thread\">;\n id: z$1.ZodOptional;\n metadata: z$1.ZodOptional;\n eventTypes: z$1.ZodOptional>>>>;\n hasPendingInteraction: z$1.ZodOptional;\n projectId: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"project\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"environment\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"host\">;\n id: z$1.ZodOptional;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"changed\">;\n entity: z$1.ZodLiteral<\"system\">;\n changes: z$1.ZodReadonly>>;\n}, z$1.core.$strict>], \"entity\">;\ntype ChangedMessage = z$1.infer;\n\ndeclare const environmentSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodNullable;\n projectId: z$1.ZodString;\n hostId: z$1.ZodString;\n path: z$1.ZodNullable;\n managed: z$1.ZodBoolean;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n branchName: z$1.ZodNullable;\n baseBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n mergeBaseBranch: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n ready: \"ready\";\n retiring: \"retiring\";\n destroying: \"destroying\";\n destroyed: \"destroyed\";\n }>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype Environment = z$1.infer;\n\n/**\n * User-opt-in experiments (the Settings → Experiments toggles). Distinct from\n * `FeatureFlags`: flags are operator-set via env at server start, experiments\n * are user-toggled at runtime and persisted server-side so server-owned\n * policy (e.g. skill injection) can honor them.\n *\n * Every experiment defaults to off — opting in is the point.\n */\ndeclare const experimentsSchema: z$1.ZodObject<{\n claudeCodeMockCliTraffic: z$1.ZodBoolean;\n plugins: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype Experiments = z$1.infer;\n\ndeclare const hostSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n type: z$1.ZodEnum<{\n persistent: \"persistent\";\n }>;\n status: z$1.ZodEnum<{\n connected: \"connected\";\n disconnected: \"disconnected\";\n }>;\n lastSeenAt: z$1.ZodNullable;\n lastRejectedProtocolVersion: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype Host = z$1.infer;\n\ninterface JsonObject {\n [key: string]: JsonValue;\n}\ntype JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;\n\ndeclare const pendingInteractionResolutionSchema: z$1.ZodUnion;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n}, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin_submitted\">;\n}, z$1.core.$strip>]>;\ntype PendingInteractionResolution = z$1.infer;\ndeclare const providerPendingInteractionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n interrupted: \"interrupted\";\n pending: \"pending\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n origin: z$1.ZodOptional;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n }, z$1.core.$strip>>;\n payload: z$1.ZodUnion;\n subject: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n itemId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n actions: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"listFiles\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"file_change\">;\n itemId: z$1.ZodString;\n writeScope: z$1.ZodNullable;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>], \"kind\">;\n reason: z$1.ZodNullable;\n availableDecisions: z$1.ZodArray>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>;\n resolution: z$1.ZodNullable;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>>;\n}, z$1.core.$strip>;\ntype ProviderPendingInteraction = z$1.infer;\ndeclare const pluginPendingInteractionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n interrupted: \"interrupted\";\n pending: \"pending\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodNullable;\n origin: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n rendererId: z$1.ZodString;\n }, z$1.core.$strip>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n title: z$1.ZodString;\n data: z$1.ZodType>;\n }, z$1.core.$strip>;\n resolution: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginPendingInteraction = z$1.infer;\ntype PendingInteraction = ProviderPendingInteraction | PluginPendingInteraction;\n\ndeclare const projectSourceSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n isDefault: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n type: z$1.ZodLiteral<\"local_path\">;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ProjectSource = z$1.infer;\n\ndeclare const resolvedThreadExecutionOptionsSchema: z$1.ZodObject<{\n seq: z$1.ZodOptional;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n source: z$1.ZodEnum<{\n \"client/thread/start\": \"client/thread/start\";\n \"client/turn/requested\": \"client/turn/requested\";\n \"client/turn/start\": \"client/turn/start\";\n }>;\n}, z$1.core.$strip>;\ntype ResolvedThreadExecutionOptions = z$1.infer;\ndeclare const projectExecutionDefaultsSchema: z$1.ZodObject<{\n providerId: z$1.ZodString;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n}, z$1.core.$strip>;\ntype ProjectExecutionDefaults = z$1.infer;\n\n/** All thread events — provider-originated or system-originated. */\ndeclare const threadEventSchema: z$1.ZodPipe;\n threadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/identity\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/started\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n }>;\n error: z$1.ZodOptional>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/input/accepted\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n clientRequestId: z$1.ZodString;\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/name/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n threadName: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/compacted\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/goal/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n objective: z$1.ZodString;\n status: z$1.ZodEnum<{\n active: \"active\";\n paused: \"paused\";\n budgetLimited: \"budgetLimited\";\n complete: \"complete\";\n }>;\n tokenBudget: z$1.ZodNullable;\n tokensUsed: z$1.ZodNumber;\n timeUsedSeconds: z$1.ZodNumber;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/goal/cleared\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/started\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"userMessage\">;\n id: z$1.ZodString;\n content: z$1.ZodArray;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n clientRequestId: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"agentMessage\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commandExecution\">;\n id: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodString;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n pending: \"pending\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n aggregatedOutput: z$1.ZodOptional;\n exitCode: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"fileChange\">;\n id: z$1.ZodString;\n changes: z$1.ZodArray;\n movePath: z$1.ZodOptional;\n diff: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n pending: \"pending\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webSearch\">;\n id: z$1.ZodString;\n queries: z$1.ZodArray;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webFetch\">;\n id: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"imageView\">;\n id: z$1.ZodString;\n path: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"toolCall\">;\n id: z$1.ZodString;\n server: z$1.ZodOptional;\n tool: z$1.ZodString;\n arguments: z$1.ZodOptional>;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n pending: \"pending\";\n }>;\n result: z$1.ZodOptional;\n error: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reasoning\">;\n id: z$1.ZodString;\n summary: z$1.ZodArray;\n content: z$1.ZodArray;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"plan\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"contextCompaction\">;\n id: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n pending: \"pending\";\n }>;\n taskStatus: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n paused: \"paused\";\n pending: \"pending\";\n running: \"running\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"userMessage\">;\n id: z$1.ZodString;\n content: z$1.ZodArray;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n clientRequestId: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"agentMessage\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commandExecution\">;\n id: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodString;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n pending: \"pending\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n aggregatedOutput: z$1.ZodOptional;\n exitCode: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"fileChange\">;\n id: z$1.ZodString;\n changes: z$1.ZodArray;\n movePath: z$1.ZodOptional;\n diff: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n pending: \"pending\";\n }>;\n approvalStatus: z$1.ZodNullable>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webSearch\">;\n id: z$1.ZodString;\n queries: z$1.ZodArray;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"webFetch\">;\n id: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n resultText: z$1.ZodNullable;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"imageView\">;\n id: z$1.ZodString;\n path: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"toolCall\">;\n id: z$1.ZodString;\n server: z$1.ZodOptional;\n tool: z$1.ZodString;\n arguments: z$1.ZodOptional>;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n pending: \"pending\";\n }>;\n result: z$1.ZodOptional;\n error: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n truncation: z$1.ZodOptional>;\n result: z$1.ZodOptional>;\n resultText: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reasoning\">;\n id: z$1.ZodString;\n summary: z$1.ZodArray;\n content: z$1.ZodArray;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"plan\">;\n id: z$1.ZodString;\n text: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"contextCompaction\">;\n id: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n pending: \"pending\";\n }>;\n taskStatus: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n paused: \"paused\";\n pending: \"pending\";\n running: \"running\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/agentMessage/delta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/commandExecution/outputDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n reset: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/fileChange/outputDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/reasoning/summaryTextDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/reasoning/textDelta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/plan/delta\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n delta: z$1.ZodString;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/mcpToolCall/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n message: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/toolCall/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n itemId: z$1.ZodString;\n message: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/backgroundTask/progress\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n pending: \"pending\";\n }>;\n taskStatus: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n paused: \"paused\";\n pending: \"pending\";\n running: \"running\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"item/backgroundTask/completed\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n item: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"backgroundTask\">;\n id: z$1.ZodString;\n taskType: z$1.ZodString;\n description: z$1.ZodString;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n interrupted: \"interrupted\";\n pending: \"pending\";\n }>;\n taskStatus: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n paused: \"paused\";\n pending: \"pending\";\n running: \"running\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n skipTranscript: z$1.ZodBoolean;\n workflowName: z$1.ZodOptional;\n workflow: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodOptional>;\n summary: z$1.ZodOptional;\n error: z$1.ZodOptional;\n outputFile: z$1.ZodOptional;\n parentToolCallId: z$1.ZodOptional;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/tokenUsage/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n tokenUsage: z$1.ZodObject<{\n total: z$1.ZodObject<{\n totalTokens: z$1.ZodNumber;\n inputTokens: z$1.ZodNumber;\n cachedInputTokens: z$1.ZodNumber;\n outputTokens: z$1.ZodNumber;\n reasoningOutputTokens: z$1.ZodNumber;\n }, z$1.core.$strip>;\n last: z$1.ZodObject<{\n totalTokens: z$1.ZodNumber;\n inputTokens: z$1.ZodNumber;\n cachedInputTokens: z$1.ZodNumber;\n outputTokens: z$1.ZodNumber;\n reasoningOutputTokens: z$1.ZodNumber;\n }, z$1.core.$strip>;\n modelContextWindow: z$1.ZodNullable;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"thread/contextWindowUsage/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n contextWindowUsage: z$1.ZodObject<{\n usedTokens: z$1.ZodNullable;\n modelContextWindow: z$1.ZodNullable;\n estimated: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/plan/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n plan: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n explanation: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"turn/diff/updated\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n diff: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/error\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n message: z$1.ZodString;\n detail: z$1.ZodOptional;\n willRetry: z$1.ZodOptional;\n errorInfo: z$1.ZodOptional;\n providerCode: z$1.ZodNullable;\n httpStatusCode: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/warning\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n category: z$1.ZodEnum<{\n deprecation: \"deprecation\";\n config: \"config\";\n general: \"general\";\n }>;\n summary: z$1.ZodOptional;\n details: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/modelFallback\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n originalModel: z$1.ZodString;\n fallbackModel: z$1.ZodString;\n reason: z$1.ZodEnum<{\n refusal: \"refusal\";\n provider: \"provider\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider/unhandled\">;\n threadId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerId: z$1.ZodString;\n rawType: z$1.ZodString;\n rawEvent: z$1.ZodObject<{\n jsonrpc: z$1.ZodLiteral<\"2.0\">;\n id: z$1.ZodOptional>;\n method: z$1.ZodString;\n params: z$1.ZodOptional>>;\n }, z$1.core.$strip>;\n parentToolCallId: z$1.ZodOptional;\n}, z$1.core.$strip>], \"type\">, z$1.ZodObject<{\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strip>>, z$1.ZodIntersection;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"client/turn/requested\">;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n requestId: z$1.ZodString;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n senderThreadId: z$1.ZodNullable;\n systemMessageKind: z$1.ZodOptional>;\n systemMessageSubject: z$1.ZodOptional;\n threadId: z$1.ZodString;\n threadName: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-batch\">;\n count: z$1.ZodNumber;\n }, z$1.core.$strip>], \"kind\">>>;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-start\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new-turn\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"auto\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"steer\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>], \"kind\">;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n execution: z$1.ZodObject<{\n seq: z$1.ZodOptional;\n model: z$1.ZodString;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n source: z$1.ZodEnum<{\n \"client/thread/start\": \"client/thread/start\";\n \"client/turn/requested\": \"client/turn/requested\";\n \"client/turn/start\": \"client/turn/start\";\n }>;\n permissionMode: z$1.ZodEnum<{\n readonly: \"readonly\";\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n \"workspace-write\": \"workspace-write\";\n }>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"client/turn/start\">;\n threadId: z$1.ZodString;\n direction: z$1.ZodLiteral<\"outbound\">;\n source: z$1.ZodEnum<{\n spawn: \"spawn\";\n tell: \"tell\";\n }>;\n initiator: z$1.ZodEnum<{\n system: \"system\";\n user: \"user\";\n agent: \"agent\";\n }>;\n request: z$1.ZodObject<{\n method: z$1.ZodEnum<{\n \"thread/start\": \"thread/start\";\n \"turn/start\": \"turn/start\";\n }>;\n params: z$1.ZodRecord;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/error\">;\n threadId: z$1.ZodString;\n code: z$1.ZodOptional;\n message: z$1.ZodString;\n detail: z$1.ZodOptional;\n reconnectAttempt: z$1.ZodOptional;\n reconnectTotal: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/manager/user_message\">;\n threadId: z$1.ZodString;\n text: z$1.ZodString;\n toolCallId: z$1.ZodOptional;\n turnId: z$1.ZodOptional;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/thread/interrupted\">;\n threadId: z$1.ZodString;\n reason: z$1.ZodEnum<{\n \"manual-stop\": \"manual-stop\";\n \"host-daemon-restarted\": \"host-daemon-restarted\";\n \"provider-turn-idle\": \"provider-turn-idle\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/operation\">;\n threadId: z$1.ZodString;\n operation: z$1.ZodString;\n status: z$1.ZodString;\n message: z$1.ZodString;\n operationId: z$1.ZodString;\n metadata: z$1.ZodOptional>>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/permissionGrant/lifecycle\">;\n threadId: z$1.ZodString;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n status: z$1.ZodEnum<{\n interrupted: \"interrupted\";\n pending: \"pending\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n resolution: z$1.ZodDefault;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">>>;\n statusReason: z$1.ZodDefault>;\n subject: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/userQuestion/lifecycle\">;\n threadId: z$1.ZodString;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n status: z$1.ZodEnum<{\n interrupted: \"interrupted\";\n pending: \"pending\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n resolution: z$1.ZodDefault;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>>;\n statusReason: z$1.ZodDefault>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/thread-provisioning\">;\n threadId: z$1.ZodString;\n provisioningId: z$1.ZodString;\n status: z$1.ZodEnum<{\n completed: \"completed\";\n failed: \"failed\";\n active: \"active\";\n cancelled: \"cancelled\";\n }>;\n environmentId: z$1.ZodString;\n entries: z$1.ZodArray;\n key: z$1.ZodString;\n text: z$1.ZodString;\n startedAt: z$1.ZodOptional;\n status: z$1.ZodOptional>;\n metadata: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"system/provider-turn-watchdog\">;\n threadId: z$1.ZodString;\n reason: z$1.ZodLiteral<\"provider-turn-idle\">;\n thresholdMs: z$1.ZodNumber;\n elapsedMs: z$1.ZodNumber;\n activeTurnId: z$1.ZodString;\n activeTurnStartedAt: z$1.ZodNumber;\n lastActivityEventSequence: z$1.ZodNumber;\n lastActivityEventType: z$1.ZodString;\n lastActivityEventAt: z$1.ZodNumber;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodNullable;\n firedAt: z$1.ZodNumber;\n}, z$1.core.$strip>]>, z$1.ZodObject<{\n scope: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n}, z$1.core.$strip>>]>>;\ntype ThreadEvent = z$1.infer;\ntype ThreadEventType = ThreadEvent[\"type\"];\n\ndeclare const providerInfoSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n displayName: z$1.ZodString;\n logoUrl: z$1.ZodNullable;\n capabilities: z$1.ZodObject<{\n supportsArchive: z$1.ZodBoolean;\n supportsRename: z$1.ZodBoolean;\n supportsServiceTier: z$1.ZodBoolean;\n supportsUserQuestion: z$1.ZodBoolean;\n supportsFork: z$1.ZodBoolean;\n supportedPermissionModes: z$1.ZodArray>;\n }, z$1.core.$strip>;\n composerActions: z$1.ZodArray;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plan\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"goal\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>], \"kind\">>;\n available: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype ProviderInfo = z$1.infer;\n\ndeclare const threadEventScopeSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"turn\">;\n turnId: z$1.ZodString;\n}, z$1.core.$strip>], \"kind\">;\ntype ThreadEventScope = z$1.infer;\n\ntype ThreadEventByType = {\n [TType in ThreadEventType]: Extract;\n};\ntype ThreadEventForType = ThreadEventByType[TType];\ntype StoredThreadEventDataFromEvent = Omit;\ninterface ThreadEventRowBase {\n id: string;\n scope: ThreadEventScope;\n threadId: string;\n seq: number;\n createdAt: number;\n actorHandle: string | null;\n}\ntype ThreadEventRowFromEvent = ThreadEventRowBase & {\n type: TEvent[\"type\"];\n data: StoredThreadEventDataFromEvent;\n};\ntype ThreadEventRowOfType = ThreadEventRowFromEvent>;\ntype ThreadEventRow = {\n [TType in ThreadEventType]: ThreadEventRowOfType;\n}[ThreadEventType];\n\ndeclare const threadStatusSchema: z$1.ZodEnum<{\n error: \"error\";\n active: \"active\";\n starting: \"starting\";\n idle: \"idle\";\n stopping: \"stopping\";\n}>;\ntype ThreadStatus = z$1.infer;\n\ndeclare const threadTimelinePendingTodosSchema: z$1.ZodObject<{\n sourceSeq: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n items: z$1.ZodArray;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ThreadTimelinePendingTodos = z$1.infer;\n\ndeclare const threadQueuedMessageSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n content: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n full: \"full\";\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadQueuedMessage = z$1.infer;\n\ndeclare const workspaceFileListResponseSchema: z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype WorkspaceFileListResponse = z$1.infer;\ndeclare const workspacePathListResponseSchema: z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype WorkspacePathListResponse = z$1.infer;\n\ndeclare const createProjectSourceRequestSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodPipe>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"clone\">;\n targetPath: z$1.ZodOptional>>;\n remoteUrl: z$1.ZodOptional;\n}, z$1.core.$strict>], \"type\">;\ntype CreateProjectSourceRequest = z$1.infer;\ndeclare const createProjectRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n source: z$1.ZodObject<{\n hostId: z$1.ZodString;\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodPipe>;\n }, z$1.core.$strict>;\n}, z$1.core.$strip>;\ntype CreateProjectRequest = z$1.infer;\ndeclare const threadSectionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadSectionResponse = z$1.infer;\ndeclare const createThreadSectionRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype CreateThreadSectionRequest = z$1.infer;\ndeclare const updateThreadSectionRequestSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateThreadSectionRequest = z$1.infer;\ndeclare const deleteThreadSectionRequestSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n}, z$1.core.$strict>;\ntype DeleteThreadSectionRequest = z$1.infer;\ndeclare const threadSectionMutationResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n name: z$1.ZodString;\n updatedThreadCount: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadSectionMutationResponse = z$1.infer;\ndeclare const reorderProjectRequestSchema: z$1.ZodObject<{\n previousProjectId: z$1.ZodNullable;\n nextProjectId: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ReorderProjectRequest = z$1.infer;\ndeclare const projectListQuerySchema: z$1.ZodObject<{\n include: z$1.ZodOptional;\n includePersonal: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype ProjectListQuery = z$1.infer;\ndeclare const projectFilesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional>;\n limit: z$1.ZodOptional>;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectFilesQuery = z$1.infer;\ndeclare const projectPathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional>;\n limit: z$1.ZodOptional>;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectPathsQuery = z$1.infer;\ndeclare const projectFileContentQuerySchema: z$1.ZodObject<{\n path: z$1.ZodString;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype ProjectFileContentQuery = z$1.infer;\ndeclare const projectBranchesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n hostId: z$1.ZodString;\n selectedBranch: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ProjectBranchesQuery = z$1.infer;\ndeclare const projectBranchesResponseSchema: z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n defaultBranch: z$1.ZodNullable;\n defaultBranchRelation: z$1.ZodNullable>;\n hasUncommittedChanges: z$1.ZodBoolean;\n operation: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"none\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"rebase\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"cherry-pick\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"revert\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>], \"kind\">;\n originDefaultBranch: z$1.ZodNullable;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n defaultWorktreeBaseBranch: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ProjectBranchesResponse = z$1.infer;\ndeclare const promptHistoryQuerySchema: z$1.ZodObject<{\n limit: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PromptHistoryQuery = z$1.infer;\ndeclare const promptHistoryResponseSchema: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>>;\ntype PromptHistoryResponse = z$1.infer;\ndeclare const updateProjectRequestSchema: z$1.ZodObject<{\n name: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype UpdateProjectRequest = z$1.infer;\ndeclare const updateProjectSourceRequestSchema: z$1.ZodObject<{\n type: z$1.ZodLiteral<\"local_path\">;\n path: z$1.ZodOptional>>;\n isDefault: z$1.ZodOptional>;\n}, z$1.core.$strict>;\ntype UpdateProjectSourceRequest = z$1.infer;\ndeclare const commandListResponseSchema: z$1.ZodObject<{\n commands: z$1.ZodArray;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n description: z$1.ZodNullable;\n argumentHint: z$1.ZodNullable;\n pluginId: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype CommandListResponse = z$1.infer;\n/** Query for the complete command catalog available to a project and provider. */\ndeclare const projectCommandsQuerySchema: z$1.ZodObject<{\n provider: z$1.ZodString;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional, z$1.ZodOptional>>;\n}, z$1.core.$strict>;\ntype ProjectCommandsQuery = z$1.infer;\ndeclare const projectResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodEnum<{\n personal: \"personal\";\n standard: \"standard\";\n }>;\n name: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n sources: z$1.ZodArray;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ProjectResponse = z$1.infer;\ndeclare const projectWithThreadsResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodEnum<{\n personal: \"personal\";\n standard: \"standard\";\n }>;\n name: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n sources: z$1.ZodArray;\n hostId: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n threads: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>>;\n defaultExecutionOptions: z$1.ZodNullable;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ProjectWithThreadsResponse = z$1.infer;\ndeclare const uploadedPromptAttachmentSchema: z$1.ZodObject<{\n type: z$1.ZodEnum<{\n localImage: \"localImage\";\n localFile: \"localFile\";\n }>;\n path: z$1.ZodString;\n name: z$1.ZodString;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype UploadedPromptAttachment = z$1.infer;\ndeclare const copyProjectAttachmentsRequestSchema: z$1.ZodObject<{\n sourceProjectId: z$1.ZodString;\n paths: z$1.ZodArray;\n}, z$1.core.$strict>;\ntype CopyProjectAttachmentsRequest = z$1.infer;\n\ndeclare const updateEnvironmentRequestSchema: z$1.ZodObject<{\n mergeBaseBranch: z$1.ZodOptional>;\n name: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype UpdateEnvironmentRequest = z$1.infer;\n/**\n * Query for searching paths in an environment's workspace. Unlike the\n * project-scoped variant this needs no `environmentId` — the environment is\n * the route param — and is project-agnostic, so it works for projectless\n * (personal) environments too.\n */\ndeclare const environmentPathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n}, z$1.core.$strip>;\ntype EnvironmentPathsQuery = z$1.infer;\ndeclare const environmentDiffBranchesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n selectedBranch: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype EnvironmentDiffBranchesQuery = z$1.infer;\ndeclare const environmentDiffBranchesResponseSchema: z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype EnvironmentDiffBranchesResponse = z$1.infer;\ndeclare const environmentStatusQuerySchema: z$1.ZodObject<{\n mergeBaseBranch: z$1.ZodOptional>;\n}, z$1.core.$strip>;\ntype EnvironmentStatusQuery = z$1.infer;\ndeclare const environmentDiffQuerySchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n target: z$1.ZodLiteral<\"uncommitted\">;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodPipe;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodPipe;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n}, z$1.core.$strip>], \"target\">;\ntype EnvironmentDiffQuery = z$1.infer;\n/**\n * Query for fetching a single file's contents at one side of a diff target.\n * Used by the diff card to reparse the card's patch with full old/new contents\n * so `@pierre/diffs` can render expand-context buttons between hunks.\n *\n * For `branch_committed` / `all`, callers pass the resolved merge-base SHA\n * (`mergeBaseRef`, surfaced by `workspace.diff`) rather than the branch name\n * — the diff itself was computed against that SHA, so reading the old side\n * from the same SHA keeps the file content aligned with the hunk line\n * numbers. Reading from the branch tip is wrong whenever the branch has\n * moved past the merge-base since the file existed there.\n */\ndeclare const environmentDiffFileQuerySchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n target: z$1.ZodLiteral<\"uncommitted\">;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseRef: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"all\">;\n mergeBaseRef: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n target: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n path: z$1.ZodString;\n side: z$1.ZodEnum<{\n new: \"new\";\n old: \"old\";\n }>;\n}, z$1.core.$strip>], \"target\">;\ntype EnvironmentDiffFileQuery = z$1.infer;\ndeclare const environmentDiffFileResponseSchema: z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n utf8: \"utf8\";\n base64: \"base64\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype EnvironmentDiffFileResponse = z$1.infer;\ndeclare const environmentArchiveThreadsResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n archivedThreadIds: z$1.ZodArray;\n}, z$1.core.$strip>;\ntype EnvironmentArchiveThreadsResponse = z$1.infer;\ndeclare const pullRequestMergeMethodSchema: z$1.ZodEnum<{\n merge: \"merge\";\n rebase: \"rebase\";\n squash: \"squash\";\n}>;\ntype PullRequestMergeMethod = z$1.infer;\ndeclare const commitActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"commit\">;\n message: z$1.ZodString;\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n}, z$1.core.$strip>;\ntype CommitActionResponse = z$1.infer;\ndeclare const squashMergeActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"squash_merge\">;\n merged: z$1.ZodBoolean;\n message: z$1.ZodString;\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SquashMergeActionResponse = z$1.infer;\ndeclare const pullRequestReadyActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_ready\">;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestReadyActionResponse = z$1.infer;\ndeclare const pullRequestMergeActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_merge\">;\n method: z$1.ZodEnum<{\n merge: \"merge\";\n rebase: \"rebase\";\n squash: \"squash\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestMergeActionResponse = z$1.infer;\ndeclare const pullRequestDraftActionResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n action: z$1.ZodLiteral<\"pull_request_draft\">;\n message: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PullRequestDraftActionResponse = z$1.infer;\ndeclare const environmentStatusResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n workspace: z$1.ZodObject<{\n workingTree: z$1.ZodObject<{\n insertions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n files: z$1.ZodArray;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n hasUncommittedChanges: z$1.ZodBoolean;\n state: z$1.ZodEnum<{\n clean: \"clean\";\n untracked: \"untracked\";\n dirty_uncommitted: \"dirty_uncommitted\";\n committed_unmerged: \"committed_unmerged\";\n dirty_and_committed_unmerged: \"dirty_and_committed_unmerged\";\n }>;\n }, z$1.core.$strip>;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n branch: z$1.ZodObject<{\n currentBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodString;\n }, z$1.core.$strip>;\n mergeBase: z$1.ZodNullable;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n mergeBaseBranch: z$1.ZodString;\n baseRef: z$1.ZodNullable;\n aheadCount: z$1.ZodNumber;\n behindCount: z$1.ZodNumber;\n hasCommittedUnmergedChanges: z$1.ZodBoolean;\n commits: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\n/**\n * Structured pull-request lookup outcome. \"absent\" is a real answer — the\n * host checked and the branch has no PR (non-git environments resolve to\n * \"absent\" without a daemon call). \"unavailable\" means the lookup itself\n * failed (gh missing, not authenticated, timeout, unreachable workspace), so\n * callers must not render it as \"no PR exists\".\n */\ndeclare const environmentPullRequestResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n pullRequest: z$1.ZodObject<{\n number: z$1.ZodNumber;\n title: z$1.ZodString;\n state: z$1.ZodEnum<{\n merged: \"merged\";\n draft: \"draft\";\n open: \"open\";\n closed: \"closed\";\n }>;\n url: z$1.ZodString;\n baseRefName: z$1.ZodString;\n headRefName: z$1.ZodString;\n updatedAt: z$1.ZodString;\n checks: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n unknown: \"unknown\";\n pending: \"pending\";\n passing: \"passing\";\n failing: \"failing\";\n no_checks: \"no_checks\";\n }>;\n totalCount: z$1.ZodNumber;\n passedCount: z$1.ZodNumber;\n failedCount: z$1.ZodNumber;\n pendingCount: z$1.ZodNumber;\n }, z$1.core.$strict>;\n review: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n none: \"none\";\n approved: \"approved\";\n changes_requested: \"changes_requested\";\n review_required: \"review_required\";\n review_requested: \"review_requested\";\n }>;\n reviewRequestCount: z$1.ZodNumber;\n }, z$1.core.$strict>;\n mergeability: z$1.ZodObject<{\n state: z$1.ZodEnum<{\n unknown: \"unknown\";\n draft: \"draft\";\n mergeable: \"mergeable\";\n conflicts: \"conflicts\";\n blocked: \"blocked\";\n }>;\n mergeStateStatus: z$1.ZodNullable>;\n mergeable: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n attention: z$1.ZodEnum<{\n none: \"none\";\n merged: \"merged\";\n draft: \"draft\";\n closed: \"closed\";\n changes_requested: \"changes_requested\";\n review_requested: \"review_requested\";\n conflicts: \"conflicts\";\n blocked: \"blocked\";\n checks_failed: \"checks_failed\";\n checks_pending: \"checks_pending\";\n ready_to_merge: \"ready_to_merge\";\n }>;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"absent\">;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n message: z$1.ZodString;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentPullRequestResponse = z$1.infer;\ndeclare const environmentDiffResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n diff: z$1.ZodObject<{\n diff: z$1.ZodString;\n truncated: z$1.ZodBoolean;\n shortstat: z$1.ZodString;\n files: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strip>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffResponse = z$1.infer;\ndeclare const environmentDiffFilesResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n files: z$1.ZodArray;\n changeKind: z$1.ZodEnum<{\n deleted: \"deleted\";\n added: \"added\";\n modified: \"modified\";\n renamed: \"renamed\";\n copied: \"copied\";\n type_changed: \"type_changed\";\n }>;\n additions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n binary: z$1.ZodBoolean;\n origin: z$1.ZodEnum<{\n untracked: \"untracked\";\n tracked: \"tracked\";\n }>;\n loadMode: z$1.ZodEnum<{\n auto: \"auto\";\n on_demand: \"on_demand\";\n too_large: \"too_large\";\n }>;\n }, z$1.core.$strip>>;\n shortstat: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n initialPatches: z$1.ZodArray>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n too_many_files: \"too_many_files\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffFilesResponse = z$1.infer;\ndeclare const environmentDiffPatchResponseSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n patches: z$1.ZodArray>;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"not_applicable\">;\n reason: z$1.ZodEnum<{\n non_git_environment: \"non_git_environment\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n unknown: \"unknown\";\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>], \"outcome\">;\ntype EnvironmentDiffPatchResponse = z$1.infer;\n/**\n * Body for `POST /diff/patch`: the diff target plus the list of new paths whose\n * patches the client wants. A POST (not GET) because the repeated `paths` array\n * cannot survive flat query parsing. The client supplies only new paths; the\n * server re-derives each file's rename/copy pairing (`previousPath`) from its\n * own TOC.\n */\ndeclare const environmentDiffPatchRequestSchema: z$1.ZodObject<{\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n paths: z$1.ZodArray;\n}, z$1.core.$strict>;\ntype EnvironmentDiffPatchRequest = z$1.infer;\ntype EnvironmentStatusResponse = z$1.infer;\n\ndeclare const providerUsageResponseSchema: z$1.ZodObject<{\n codex: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n claudeCode: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n cursor: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n}, z$1.core.$strip>;\ntype ProviderUsageResponse = z$1.infer;\ntype HostDaemonCommandTransport = \"settled\" | \"onlineRpc\";\ntype HostDaemonCommandEnvironmentLane = \"read\" | \"write\";\ntype HostDaemonFlushEventsBeforeResult = boolean | \"when-initiated\";\ninterface HostDaemonCommandDescriptor {\n type: Type;\n schema: Schema;\n resultSchema: ResultSchema;\n transport: Transport;\n retryable: Retryable;\n flushEventsBeforeResult: HostDaemonFlushEventsBeforeResult;\n envLane: HostDaemonCommandEnvironmentLane | null;\n}\ndeclare const hostDaemonCommandRegistry: {\n \"thread.start\": HostDaemonCommandDescriptor<\"thread.start\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n projectId: z$1.ZodString;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n options: z$1.ZodIntersection;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n claudeCodePermissionMode: z$1.ZodOptional>;\n claudeCodeMockCliTraffic: z$1.ZodOptional>;\n workflowsEnabled: z$1.ZodBoolean;\n memoryEnabled: z$1.ZodOptional;\n providerSubagentsEnabled: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"accept-edits\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"user\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"auto\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"automatic\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"full\">;\n permissionScope: z$1.ZodLiteral<\"full\">;\n approvalReviewer: z$1.ZodNull;\n permissionEscalation: z$1.ZodNull;\n }, z$1.core.$strip>], \"permissionMode\">>;\n instructions: z$1.ZodString;\n dynamicTools: z$1.ZodArray>;\n injectedSkillSources: z$1.ZodArray;\n treeHash: z$1.ZodString;\n entryPath: z$1.ZodString;\n sourceType: z$1.ZodEnum<{\n builtin: \"builtin\";\n \"data-dir\": \"data-dir\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n name: z$1.ZodString;\n description: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-path\">;\n sourceType: z$1.ZodLiteral<\"project\">;\n sourceRootPath: z$1.ZodString;\n skillFilePath: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n disallowedTools: z$1.ZodOptional>;\n instructionMode: z$1.ZodEnum<{\n append: \"append\";\n replace: \"replace\";\n }>;\n type: z$1.ZodLiteral<\"thread.start\">;\n requestId: z$1.ZodString;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n speaker: z$1.ZodOptional>;\n threadStoragePath: z$1.ZodOptional;\n fork: z$1.ZodOptional>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"turn.submit\": HostDaemonCommandDescriptor<\"turn.submit\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"turn.submit\">;\n requestId: z$1.ZodString;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n inputGroups: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n builtin: \"builtin\";\n project: \"project\";\n user: \"user\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>>>;\n speaker: z$1.ZodOptional>;\n options: z$1.ZodIntersection;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n claudeCodePermissionMode: z$1.ZodOptional>;\n claudeCodeMockCliTraffic: z$1.ZodOptional>;\n workflowsEnabled: z$1.ZodBoolean;\n memoryEnabled: z$1.ZodOptional;\n providerSubagentsEnabled: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"accept-edits\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"user\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"auto\">;\n permissionScope: z$1.ZodLiteral<\"workspace\">;\n approvalReviewer: z$1.ZodLiteral<\"automatic\">;\n permissionEscalation: z$1.ZodEnum<{\n ask: \"ask\";\n deny: \"deny\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n permissionMode: z$1.ZodLiteral<\"full\">;\n permissionScope: z$1.ZodLiteral<\"full\">;\n approvalReviewer: z$1.ZodNull;\n permissionEscalation: z$1.ZodNull;\n }, z$1.core.$strip>], \"permissionMode\">>;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n resumeContext: z$1.ZodObject<{\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n instructionMode: z$1.ZodEnum<{\n append: \"append\";\n replace: \"replace\";\n }>;\n projectId: z$1.ZodString;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n instructions: z$1.ZodString;\n dynamicTools: z$1.ZodArray>;\n injectedSkillSources: z$1.ZodArray;\n treeHash: z$1.ZodString;\n entryPath: z$1.ZodString;\n sourceType: z$1.ZodEnum<{\n builtin: \"builtin\";\n \"data-dir\": \"data-dir\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n name: z$1.ZodString;\n description: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-path\">;\n sourceType: z$1.ZodLiteral<\"project\">;\n sourceRootPath: z$1.ZodString;\n skillFilePath: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n disallowedTools: z$1.ZodOptional>;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"start\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"auto\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"steer\">;\n expectedTurnId: z$1.ZodNullable;\n }, z$1.core.$strip>], \"mode\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n appliedAs: z$1.ZodEnum<{\n steer: \"steer\";\n \"new-turn\": \"new-turn\";\n }>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"thread.stop\": HostDaemonCommandDescriptor<\"thread.stop\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.stop\">;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.rename\": HostDaemonCommandDescriptor<\"thread.rename\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.rename\">;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.archive\": HostDaemonCommandDescriptor<\"thread.archive\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"thread.archive\">;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"thread.unarchive\": HostDaemonCommandDescriptor<\"thread.unarchive\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"thread.unarchive\">;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"interactive.resolve\": HostDaemonCommandDescriptor<\"interactive.resolve\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n threadId: z$1.ZodString;\n type: z$1.ZodLiteral<\"interactive.resolve\">;\n interactionId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n resolution: z$1.ZodUnion;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin_submitted\">;\n }, z$1.core.$strip>]>;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"codex.inference.complete\": HostDaemonCommandDescriptor<\"codex.inference.complete\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"codex.inference.complete\">;\n model: z$1.ZodString;\n prompt: z$1.ZodString;\n outputSchema: z$1.ZodType>;\n timeoutMs: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n model: z$1.ZodString;\n value: z$1.ZodType>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"codex.voice.transcribe\": HostDaemonCommandDescriptor<\"codex.voice.transcribe\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"codex.voice.transcribe\">;\n model: z$1.ZodString;\n audioBase64: z$1.ZodString;\n mimeType: z$1.ZodString;\n filename: z$1.ZodString;\n prompt: z$1.ZodNullable;\n timeoutMs: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n model: z$1.ZodString;\n text: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"environment.provision\": HostDaemonCommandDescriptor<\"environment.provision\", z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n workspaceProvisionType: z$1.ZodLiteral<\"unmanaged\">;\n path: z$1.ZodString;\n checkout: z$1.ZodOptional;\n name: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new\">;\n name: z$1.ZodString;\n baseBranch: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n sourcePath: z$1.ZodString;\n targetPath: z$1.ZodString;\n branchName: z$1.ZodString;\n baseBranch: z$1.ZodNullable;\n setupTimeoutMs: z$1.ZodNumber;\n workspaceProvisionType: z$1.ZodLiteral<\"managed-worktree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision\">;\n initiator: z$1.ZodNullable>;\n workspaceProvisionType: z$1.ZodLiteral<\"personal\">;\n targetPath: z$1.ZodString;\n }, z$1.core.$strict>], \"workspaceProvisionType\">, z$1.ZodObject<{\n path: z$1.ZodString;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n branchName: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n transcript: z$1.ZodArray;\n key: z$1.ZodString;\n text: z$1.ZodString;\n startedAt: z$1.ZodOptional;\n status: z$1.ZodOptional>;\n metadata: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"settled\", false>;\n \"project.clone\": HostDaemonCommandDescriptor<\"project.clone\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.clone\">;\n remoteUrl: z$1.ZodString;\n projectSlug: z$1.ZodString;\n targetPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n }, z$1.core.$strict>, \"settled\", false>;\n \"environment.provision.cancel\": HostDaemonCommandDescriptor<\"environment.provision.cancel\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n type: z$1.ZodLiteral<\"environment.provision.cancel\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n aborted: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"settled\", false>;\n \"environment.destroy\": HostDaemonCommandDescriptor<\"environment.destroy\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"environment.destroy\">;\n }, z$1.core.$strict>, z$1.ZodObject<{}, z$1.core.$strip>, \"settled\", false>;\n \"workspace.commit\": HostDaemonCommandDescriptor<\"workspace.commit\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.commit\">;\n message: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n }, z$1.core.$strip>, \"settled\", false>;\n \"workspace.squash_merge\": HostDaemonCommandDescriptor<\"workspace.squash_merge\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.squash_merge\">;\n targetBranch: z$1.ZodString;\n commitMessage: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commitSha: z$1.ZodString;\n commitSubject: z$1.ZodString;\n merged: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"settled\", false>;\n \"workspace.pull_request_action\": HostDaemonCommandDescriptor<\"workspace.pull_request_action\", z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"ready\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"draft\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request_action\">;\n operation: z$1.ZodLiteral<\"merge\">;\n method: z$1.ZodEnum<{\n merge: \"merge\";\n squash: \"squash\";\n rebase: \"rebase\";\n }>;\n }, z$1.core.$strict>], \"operation\">, z$1.ZodObject<{}, z$1.core.$strict>, \"settled\", false>;\n \"host.list_files\": HostDaemonCommandDescriptor<\"host.list_files\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_files\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n }, z$1.core.$strip>, z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.list_paths\": HostDaemonCommandDescriptor<\"host.list_paths\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_paths\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n includeFiles: z$1.ZodBoolean;\n includeDirectories: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.mkdir\": HostDaemonCommandDescriptor<\"host.mkdir\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.mkdir\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n recursive: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.move_path\": HostDaemonCommandDescriptor<\"host.move_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.move_path\">;\n sourcePath: z$1.ZodString;\n destinationPath: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.remove_path\": HostDaemonCommandDescriptor<\"host.remove_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.remove_path\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n recursive: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"host.browse_directory\": HostDaemonCommandDescriptor<\"host.browse_directory\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.browse_directory\">;\n path: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n directory: z$1.ZodString;\n parent: z$1.ZodNullable;\n entries: z$1.ZodArray;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.paths_exist\": HostDaemonCommandDescriptor<\"host.paths_exist\", z$1.ZodObject<{\n paths: z$1.ZodPipe, z$1.ZodTransform>;\n type: z$1.ZodLiteral<\"host.paths_exist\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n existence: z$1.ZodRecord;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"project.inspect\": HostDaemonCommandDescriptor<\"project.inspect\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.inspect\">;\n path: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n gitRemoteUrl: z$1.ZodNullable;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"project.clone_default_path\": HostDaemonCommandDescriptor<\"project.clone_default_path\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project.clone_default_path\">;\n projectSlug: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"host.pick_folder\": HostDaemonCommandDescriptor<\"host.pick_folder\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.pick_folder\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, \"onlineRpc\", false>;\n \"host.caffeinate\": HostDaemonCommandDescriptor<\"host.caffeinate\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.caffeinate\">;\n enabled: z$1.ZodBoolean;\n }, z$1.core.$strict>, z$1.ZodObject<{\n enabled: z$1.ZodBoolean;\n supported: z$1.ZodBoolean;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"connect-tunnel.ensure-identity\": HostDaemonCommandDescriptor<\"connect-tunnel.ensure-identity\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"connect-tunnel.ensure-identity\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n label: z$1.ZodString;\n baseDomain: z$1.ZodString;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"host.list_commands\": HostDaemonCommandDescriptor<\"host.list_commands\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_commands\">;\n providerId: z$1.ZodString;\n cwd: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n commands: z$1.ZodArray;\n origin: z$1.ZodEnum<{\n project: \"project\";\n user: \"user\";\n }>;\n description: z$1.ZodNullable;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.list_branches\": HostDaemonCommandDescriptor<\"host.list_branches\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.list_branches\">;\n path: z$1.ZodString;\n query: z$1.ZodOptional;\n selectedBranch: z$1.ZodOptional;\n limit: z$1.ZodNumber;\n }, z$1.core.$strip>, z$1.ZodObject<{\n branches: z$1.ZodArray;\n branchesTruncated: z$1.ZodBoolean;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n defaultBranch: z$1.ZodNullable;\n defaultBranchRelation: z$1.ZodNullable>;\n hasUncommittedChanges: z$1.ZodBoolean;\n operation: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"none\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"rebase\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"cherry-pick\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"revert\">;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n hasConflicts: z$1.ZodBoolean;\n }, z$1.core.$strip>], \"kind\">;\n originDefaultBranch: z$1.ZodNullable;\n remoteBranches: z$1.ZodArray;\n remoteBranchesTruncated: z$1.ZodBoolean;\n selectedBranch: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.file_metadata\": HostDaemonCommandDescriptor<\"host.file_metadata\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.file_metadata\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n modifiedAtMs: z$1.ZodNumber;\n sizeBytes: z$1.ZodNumber;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.read_file\": HostDaemonCommandDescriptor<\"host.read_file\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.read_file\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n ref: z$1.ZodOptional;\n }, z$1.core.$strip>, z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n modifiedAtMs: z$1.ZodOptional;\n sha256: z$1.ZodString;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.read_file_relative\": HostDaemonCommandDescriptor<\"host.read_file_relative\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.read_file_relative\">;\n rootPath: z$1.ZodString;\n path: z$1.ZodString;\n dotfiles: z$1.ZodEnum<{\n deny: \"deny\";\n allow: \"allow\";\n }>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n path: z$1.ZodString;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n mimeType: z$1.ZodOptional;\n sizeBytes: z$1.ZodNumber;\n modifiedAtMs: z$1.ZodOptional;\n sha256: z$1.ZodString;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"host.write_file\": HostDaemonCommandDescriptor<\"host.write_file\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host.write_file\">;\n path: z$1.ZodString;\n rootPath: z$1.ZodOptional;\n content: z$1.ZodString;\n contentEncoding: z$1.ZodEnum<{\n base64: \"base64\";\n utf8: \"utf8\";\n }>;\n createParents: z$1.ZodBoolean;\n expectedSha256: z$1.ZodOptional>;\n mode: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"written\">;\n sha256: z$1.ZodString;\n sizeBytes: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"conflict\">;\n currentSha256: z$1.ZodNullable;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", false>;\n \"provider.list_models\": HostDaemonCommandDescriptor<\"provider.list_models\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider.list_models\">;\n providerId: z$1.ZodString;\n acpLaunchSpec: z$1.ZodOptional;\n env: z$1.ZodRecord;\n cwd: z$1.ZodOptional;\n modelCli: z$1.ZodOptional;\n selectFlag: z$1.ZodOptional;\n primaryModels: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodTransform<{\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n } | undefined, {\n listArgs: string[];\n primaryModels: string[];\n selectFlag?: string | undefined;\n }>>>;\n reasoningCli: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n nativeReasoning: z$1.ZodOptional>;\n levelValues: z$1.ZodOptional & z$1.core.$partial, z$1.ZodString>>;\n defaultLevel: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n permissionCli: z$1.ZodOptional>;\n workspaceWrite: z$1.ZodOptional>;\n readonly: z$1.ZodOptional>;\n insertAfterArgs: z$1.ZodOptional;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n models: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n selectedOnlyModels: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"known_acp_agents.status\": HostDaemonCommandDescriptor<\"known_acp_agents.status\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"known_acp_agents.status\">;\n agents: z$1.ZodArray>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n agents: z$1.ZodArray;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>, \"onlineRpc\", true>;\n \"provider.usage\": HostDaemonCommandDescriptor<\"provider.usage\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider.usage\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n codex: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n claudeCode: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n cursor: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n status: z$1.ZodLiteral<\"ok\">;\n accountEmail: z$1.ZodNullable;\n planLabel: z$1.ZodNullable;\n windows: z$1.ZodArray;\n cost: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"not_installed\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"unauthenticated\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"expired\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n status: z$1.ZodLiteral<\"error\">;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"status\">;\n }, z$1.core.$strip>, \"onlineRpc\", true>;\n \"provider_cli.status\": HostDaemonCommandDescriptor<\"provider_cli.status\", z$1.ZodObject<{\n type: z$1.ZodLiteral<\"provider_cli.status\">;\n }, z$1.core.$strict>, z$1.ZodRecord, z$1.ZodObject<{\n displayName: z$1.ZodString;\n executableName: z$1.ZodString;\n executablePath: z$1.ZodNullable;\n installed: z$1.ZodBoolean;\n installSource: z$1.ZodEnum<{\n external: \"external\";\n notInstalled: \"notInstalled\";\n npmGlobal: \"npmGlobal\";\n }>;\n currentVersion: z$1.ZodNullable;\n latestVersion: z$1.ZodNullable;\n minimumSupportedVersion: z$1.ZodNullable;\n npmPackageName: z$1.ZodNullable;\n npmGlobalPackageVersion: z$1.ZodNullable;\n installAction: z$1.ZodNullable;\n label: z$1.ZodEnum<{\n Install: \"Install\";\n Update: \"Update\";\n }>;\n commandKind: z$1.ZodEnum<{\n exec: \"exec\";\n shell: \"shell\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>>;\n needsUpdate: z$1.ZodBoolean;\n versionUnsupported: z$1.ZodBoolean;\n }, z$1.core.$strip>>, \"onlineRpc\", true>;\n \"provider_cli.install\": HostDaemonCommandDescriptor<\"provider_cli.install\", z$1.ZodObject<{\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n actionKind: z$1.ZodEnum<{\n install: \"install\";\n update: \"update\";\n }>;\n type: z$1.ZodLiteral<\"provider_cli.install\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n events: z$1.ZodArray;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"output\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n stream: z$1.ZodEnum<{\n stdout: \"stdout\";\n stderr: \"stderr\";\n }>;\n text: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"completed\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n exitCode: z$1.ZodNullable;\n signal: z$1.ZodNullable;\n success: z$1.ZodBoolean;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"error\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n message: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n }, z$1.core.$strict>, \"onlineRpc\", false>;\n \"workspace.status\": HostDaemonCommandDescriptor<\"workspace.status\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.status\">;\n mergeBaseBranch: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n workspaceStatus: z$1.ZodObject<{\n workingTree: z$1.ZodObject<{\n insertions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n files: z$1.ZodArray;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n hasUncommittedChanges: z$1.ZodBoolean;\n state: z$1.ZodEnum<{\n clean: \"clean\";\n untracked: \"untracked\";\n dirty_uncommitted: \"dirty_uncommitted\";\n committed_unmerged: \"committed_unmerged\";\n dirty_and_committed_unmerged: \"dirty_and_committed_unmerged\";\n }>;\n }, z$1.core.$strip>;\n checkout: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"branch\">;\n branchName: z$1.ZodString;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"detached\">;\n headSha: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unborn\">;\n branchName: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"unknown\">;\n reason: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">;\n branch: z$1.ZodObject<{\n currentBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodString;\n }, z$1.core.$strip>;\n mergeBase: z$1.ZodNullable;\n insertions: z$1.ZodNullable;\n deletions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n mergeBaseBranch: z$1.ZodString;\n baseRef: z$1.ZodNullable;\n aheadCount: z$1.ZodNumber;\n behindCount: z$1.ZodNumber;\n hasCommittedUnmergedChanges: z$1.ZodBoolean;\n commits: z$1.ZodArray>;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n unknown: \"unknown\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diff\": HostDaemonCommandDescriptor<\"workspace.diff\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diff\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n maxDiffBytes: z$1.ZodNumber;\n maxFileListBytes: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n diff: z$1.ZodObject<{\n diff: z$1.ZodString;\n truncated: z$1.ZodBoolean;\n shortstat: z$1.ZodString;\n files: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strip>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n unknown: \"unknown\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diffFiles\": HostDaemonCommandDescriptor<\"workspace.diffFiles\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diffFiles\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n files: z$1.ZodArray;\n statusLetter: z$1.ZodEnum<{\n M: \"M\";\n A: \"A\";\n D: \"D\";\n R: \"R\";\n C: \"C\";\n T: \"T\";\n }>;\n additions: z$1.ZodNumber;\n deletions: z$1.ZodNumber;\n binary: z$1.ZodBoolean;\n origin: z$1.ZodEnum<{\n untracked: \"untracked\";\n tracked: \"tracked\";\n }>;\n }, z$1.core.$strip>>;\n shortstat: z$1.ZodString;\n mergeBaseRef: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n unknown: \"unknown\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.diffPatch\": HostDaemonCommandDescriptor<\"workspace.diffPatch\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.diffPatch\">;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"uncommitted\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"branch_committed\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"all\">;\n mergeBaseBranch: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"commit\">;\n sha: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">;\n paths: z$1.ZodArray;\n maxBytesPerFile: z$1.ZodNumber;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n patches: z$1.ZodArray>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n failure: z$1.ZodObject<{\n code: z$1.ZodEnum<{\n path_not_found: \"path_not_found\";\n not_git_repo: \"not_git_repo\";\n not_worktree: \"not_worktree\";\n workspace_type_mismatch: \"workspace_type_mismatch\";\n permission_denied: \"permission_denied\";\n unknown_environment: \"unknown_environment\";\n unknown: \"unknown\";\n }>;\n workspacePath: z$1.ZodString;\n message: z$1.ZodString;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n \"workspace.pull_request\": HostDaemonCommandDescriptor<\"workspace.pull_request\", z$1.ZodObject<{\n environmentId: z$1.ZodString;\n workspaceContext: z$1.ZodObject<{\n workspacePath: z$1.ZodString;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n }, z$1.core.$strip>;\n type: z$1.ZodLiteral<\"workspace.pull_request\">;\n }, z$1.core.$strict>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"available\">;\n pullRequest: z$1.ZodObject<{\n number: z$1.ZodNumber;\n title: z$1.ZodString;\n state: z$1.ZodEnum<{\n OPEN: \"OPEN\";\n CLOSED: \"CLOSED\";\n MERGED: \"MERGED\";\n }>;\n url: z$1.ZodString;\n isDraft: z$1.ZodBoolean;\n baseRefName: z$1.ZodString;\n headRefName: z$1.ZodString;\n updatedAt: z$1.ZodString;\n checks: z$1.ZodArray;\n conclusion: z$1.ZodNullable>;\n url: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n reviewDecision: z$1.ZodNullable>;\n reviewRequestCount: z$1.ZodNumber;\n mergeStateStatus: z$1.ZodNullable>;\n mergeable: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"absent\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n outcome: z$1.ZodLiteral<\"unavailable\">;\n message: z$1.ZodString;\n }, z$1.core.$strict>], \"outcome\">, \"onlineRpc\", true>;\n};\ntype HostDaemonCommandRegistry = typeof hostDaemonCommandRegistry;\ntype AnyHostDaemonCommandDescriptor = HostDaemonCommandRegistry[keyof HostDaemonCommandRegistry];\ntype HostDaemonCommandDescriptorForTransport = Extract;\ntype HostDaemonResultSchemaMapForTransport = {\n [Descriptor in HostDaemonCommandDescriptorForTransport as Descriptor[\"type\"]]: Descriptor[\"resultSchema\"];\n};\ntype HostDaemonOnlineRpcResultSchemaMap = HostDaemonResultSchemaMapForTransport<\"onlineRpc\">;\ntype HostDaemonOnlineRpcResultByType = {\n [K in keyof HostDaemonOnlineRpcResultSchemaMap]: z$1.infer;\n};\n\ndeclare const pickFolderResponseSchema: z$1.ZodObject<{\n path: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype PickFolderResponse = z$1.infer;\ndeclare const pathsExistRequestSchema: z$1.ZodObject<{\n paths: z$1.ZodPipe, z$1.ZodTransform>;\n}, z$1.core.$strip>;\ntype PathsExistRequest = z$1.infer;\ndeclare const pathsExistResponseSchema: z$1.ZodObject<{\n existence: z$1.ZodRecord;\n}, z$1.core.$strip>;\ntype PathsExistResponse = z$1.infer;\ndeclare const providerCliStatusResponseSchema: z$1.ZodRecord, z$1.ZodObject<{\n displayName: z$1.ZodString;\n executableName: z$1.ZodString;\n executablePath: z$1.ZodNullable;\n installed: z$1.ZodBoolean;\n installSource: z$1.ZodEnum<{\n external: \"external\";\n notInstalled: \"notInstalled\";\n npmGlobal: \"npmGlobal\";\n }>;\n currentVersion: z$1.ZodNullable;\n latestVersion: z$1.ZodNullable;\n minimumSupportedVersion: z$1.ZodNullable;\n npmPackageName: z$1.ZodNullable;\n npmGlobalPackageVersion: z$1.ZodNullable;\n installAction: z$1.ZodNullable;\n label: z$1.ZodEnum<{\n Install: \"Install\";\n Update: \"Update\";\n }>;\n commandKind: z$1.ZodEnum<{\n exec: \"exec\";\n shell: \"shell\";\n }>;\n command: z$1.ZodString;\n }, z$1.core.$strip>>;\n needsUpdate: z$1.ZodBoolean;\n versionUnsupported: z$1.ZodBoolean;\n}, z$1.core.$strip>>;\ntype ProviderCliStatusResponse = z$1.infer;\ndeclare const providerCliInstallRequestSchema: z$1.ZodObject<{\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n actionKind: z$1.ZodEnum<{\n install: \"install\";\n update: \"update\";\n }>;\n}, z$1.core.$strip>;\ntype ProviderCliInstallRequest = z$1.infer;\ndeclare const providerCliInstallEventSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"started\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n command: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"output\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n stream: z$1.ZodEnum<{\n stdout: \"stdout\";\n stderr: \"stderr\";\n }>;\n text: z$1.ZodString;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"completed\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n exitCode: z$1.ZodNullable;\n signal: z$1.ZodNullable;\n success: z$1.ZodBoolean;\n}, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"error\">;\n provider: z$1.ZodEnum<{\n codex: \"codex\";\n claudeCode: \"claudeCode\";\n cursor: \"cursor\";\n }>;\n message: z$1.ZodString;\n}, z$1.core.$strip>], \"type\">;\ntype ProviderCliInstallEvent = z$1.infer;\n\ninterface CreateFilePreviewResponse {\n baseUrl: string;\n expiresAtMs: number;\n}\ntype HostFileReadResponse = HostDaemonOnlineRpcResultByType[\"host.read_file\"];\ntype HostFileWriteResponse = HostDaemonOnlineRpcResultByType[\"host.write_file\"];\ntype HostFileListResponse = HostDaemonOnlineRpcResultByType[\"host.list_files\"];\ntype HostPathListResponse = HostDaemonOnlineRpcResultByType[\"host.list_paths\"];\ntype HostMkdirResponse = HostDaemonOnlineRpcResultByType[\"host.mkdir\"];\ntype HostMovePathResponse = HostDaemonOnlineRpcResultByType[\"host.move_path\"];\ntype HostRemovePathResponse = HostDaemonOnlineRpcResultByType[\"host.remove_path\"];\n\n/**\n * Query for `GET /hosts/:id/directory`, the interactive path browser's\n * single-level directory read. `path` is an absolute directory on the host;\n * omitting it lists the host's home directory (the daemon resolves it, since a\n * remote caller cannot know the host's home).\n */\ndeclare const hostDirectoryQuerySchema: z$1.ZodObject<{\n path: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype HostDirectoryQuery = z$1.infer;\ndeclare const hostDirectoryListingSchema: z$1.ZodObject<{\n directory: z$1.ZodString;\n parent: z$1.ZodNullable;\n entries: z$1.ZodArray;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype HostDirectoryListing = z$1.infer;\n/** Project name is sent so the daemon can derive its host-local checkout path. */\ndeclare const hostCloneDefaultPathQuerySchema: z$1.ZodObject<{\n projectId: z$1.ZodString;\n}, z$1.core.$strip>;\ntype HostCloneDefaultPathQuery = z$1.infer;\ndeclare const hostCloneDefaultPathResponseSchema: z$1.ZodObject<{\n path: z$1.ZodString;\n}, z$1.core.$strict>;\ntype HostCloneDefaultPathResponse = z$1.infer;\ndeclare const createHostJoinCodeResponseSchema: z$1.ZodObject<{\n joinCode: z$1.ZodString;\n hostId: z$1.ZodString;\n expiresAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype CreateHostJoinCodeResponse = z$1.infer;\ndeclare const updateHostRequestSchema: z$1.ZodObject<{\n name: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateHostRequest = z$1.infer;\ntype HostPathsExistRequest = PathsExistRequest;\ntype HostPathsExistResponse = PathsExistResponse;\ndeclare const hostPickFolderRequestSchema: z$1.ZodObject<{\n clientHostId: z$1.ZodString;\n}, z$1.core.$strict>;\ntype HostPickFolderRequest = z$1.infer;\ntype HostPickFolderResponse = PickFolderResponse;\ntype HostProviderCliStatusResponse = ProviderCliStatusResponse;\ntype HostProviderCliInstallRequest = ProviderCliInstallRequest;\ntype HostProviderCliInstallEvent = ProviderCliInstallEvent;\n\ndeclare const memberSchema: z$1.ZodObject<{\n userId: z$1.ZodString;\n handle: z$1.ZodString;\n displayName: z$1.ZodString;\n imageUrl: z$1.ZodNullable;\n addedByUserId: z$1.ZodString;\n createdAt: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype Member = z$1.infer;\n\ndeclare const pluginUpdateCheckEntrySchema: z$1.ZodObject<{\n id: z$1.ZodString;\n outcome: z$1.ZodEnum<{\n unavailable: \"unavailable\";\n incompatible: \"incompatible\";\n current: \"current\";\n \"update-available\": \"update-available\";\n pinned: \"pinned\";\n }>;\n devMode: z$1.ZodOptional>;\n installed: z$1.ZodObject<{\n version: z$1.ZodString;\n display: z$1.ZodString;\n }, z$1.core.$strip>;\n candidate: z$1.ZodOptional>;\n blocked: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n detail: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PluginUpdateCheckEntry = z$1.infer;\ndeclare const pluginApplyUpdateResultSchema: z$1.ZodObject<{\n applied: z$1.ZodBoolean;\n from: z$1.ZodObject<{\n version: z$1.ZodString;\n display: z$1.ZodString;\n }, z$1.core.$strip>;\n to: z$1.ZodOptional>;\n outcome: z$1.ZodEnum<{\n current: \"current\";\n updated: \"updated\";\n \"rolled-back\": \"rolled-back\";\n }>;\n detail: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype PluginApplyUpdateResult$1 = z$1.infer;\ndeclare const pluginSourceDetailSchema: z$1.ZodObject<{\n requested: z$1.ZodString;\n resolved: z$1.ZodString;\n integrity: z$1.ZodOptional;\n registry: z$1.ZodOptional;\n engines: z$1.ZodObject<{\n bb: z$1.ZodOptional;\n bbPluginSdk: z$1.ZodOptional;\n }, z$1.core.$strip>;\n installedAt: z$1.ZodOptional;\n history: z$1.ZodArray>;\n}, z$1.core.$strip>;\ntype PluginSourceDetail = z$1.infer;\ndeclare const installedPluginSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n source: z$1.ZodString;\n rootDir: z$1.ZodString;\n version: z$1.ZodString;\n provenance: z$1.ZodEnum<{\n builtin: \"builtin\";\n direct: \"direct\";\n catalog: \"catalog\";\n }>;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n missing: \"missing\";\n incompatible: \"incompatible\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype InstalledPlugin = z$1.infer;\ndeclare const pluginListResponseSchema: z$1.ZodObject<{\n enabled: z$1.ZodBoolean;\n plugins: z$1.ZodArray;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n missing: \"missing\";\n incompatible: \"incompatible\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginListResponse = z$1.infer;\ndeclare const pluginReloadResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n plugins: z$1.ZodArray;\n isOrphanedBuiltin: z$1.ZodBoolean;\n catalogEntryId: z$1.ZodOptional;\n sourceDisplay: z$1.ZodString;\n updateState: z$1.ZodObject<{\n outcome: z$1.ZodOptional>;\n availableVersion: z$1.ZodOptional;\n blockedVersion: z$1.ZodOptional;\n blockedReasons: z$1.ZodOptional>;\n lastCheckAt: z$1.ZodOptional;\n lastFailure: z$1.ZodOptional>;\n }, z$1.core.$strip>;\n enabled: z$1.ZodBoolean;\n description: z$1.ZodNullable;\n name: z$1.ZodNullable;\n icon: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n running: \"running\";\n missing: \"missing\";\n incompatible: \"incompatible\";\n disabled: \"disabled\";\n degraded: \"degraded\";\n \"needs-configuration\": \"needs-configuration\";\n }>;\n statusDetail: z$1.ZodNullable;\n handlerStats: z$1.ZodObject<{\n count: z$1.ZodNumber;\n totalMs: z$1.ZodNumber;\n maxMs: z$1.ZodNumber;\n errorCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n services: z$1.ZodArray;\n }, z$1.core.$strip>>;\n schedules: z$1.ZodArray;\n lastStatus: z$1.ZodNullable>;\n lastError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n cliCommand: z$1.ZodNullable>;\n hasSettings: z$1.ZodBoolean;\n app: z$1.ZodObject<{\n hasApp: z$1.ZodBoolean;\n bundle: z$1.ZodNullable;\n hash: z$1.ZodString;\n sdkMajor: z$1.ZodNumber;\n sdkVersion: z$1.ZodString;\n compatible: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>;\n logoUrl: z$1.ZodNullable;\n logoDarkUrl: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype PluginReloadResponse = z$1.infer;\ndeclare const pluginRemoveResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n}, z$1.core.$strip>;\ntype PluginRemoveResponse = z$1.infer;\ndeclare const pluginSettingsResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n schema: z$1.ZodRecord;\n secret: z$1.ZodOptional>;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"boolean\">;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"select\">;\n options: z$1.ZodArray;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project\">;\n default: z$1.ZodOptional;\n label: z$1.ZodString;\n description: z$1.ZodOptional;\n }, z$1.core.$strict>], \"type\">>;\n values: z$1.ZodRecord>>;\n}, z$1.core.$strip>;\ntype PluginSettingsResponse = z$1.infer;\ndeclare const pluginTokenResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n token: z$1.ZodString;\n}, z$1.core.$strip>;\ntype PluginTokenResponse = z$1.infer;\ndeclare const pluginCatalogStatusSchema: z$1.ZodObject<{\n pluginCount: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype PluginCatalogStatus = z$1.infer;\ndeclare const pluginCatalogSearchResultSchema: z$1.ZodObject<{\n entryId: z$1.ZodString;\n displayName: z$1.ZodString;\n description: z$1.ZodString;\n icon: z$1.ZodNullable;\n category: z$1.ZodString;\n source: z$1.ZodString;\n installed: z$1.ZodBoolean;\n compatible: z$1.ZodBoolean;\n incompatibleReason: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype PluginCatalogSearchResult$1 = z$1.infer;\n\n/**\n * Complete current ephemeral viewer rosters, keyed by thread id.\n *\n * Unlike this HTTP snapshot, realtime `presence-summary` messages are partial\n * patches: merge each supplied thread entry into the local summary, and remove\n * an entry when its supplied handle array is empty.\n */\ndeclare const presenceSnapshotResponseSchema: z$1.ZodObject<{\n threads: z$1.ZodRecord;\n typing: z$1.ZodBoolean;\n }, z$1.core.$strict>>>>;\n}, z$1.core.$strict>;\ntype PresenceSnapshotResponse = z$1.infer;\n\ndeclare const systemExecutionOptionsResponseSchema: z$1.ZodObject<{\n providers: z$1.ZodArray;\n capabilities: z$1.ZodObject<{\n supportsArchive: z$1.ZodBoolean;\n supportsRename: z$1.ZodBoolean;\n supportsServiceTier: z$1.ZodBoolean;\n supportsUserQuestion: z$1.ZodBoolean;\n supportsFork: z$1.ZodBoolean;\n supportedPermissionModes: z$1.ZodArray>;\n }, z$1.core.$strip>;\n composerActions: z$1.ZodArray;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plan\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"goal\">;\n command: z$1.ZodObject<{\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n trailingText: z$1.ZodString;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>], \"kind\">>;\n available: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n models: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n selectedOnlyModels: z$1.ZodArray;\n description: z$1.ZodString;\n }, z$1.core.$strip>>;\n defaultReasoningEffort: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n isDefault: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n modelLoadError: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype SystemExecutionOptionsResponse = z$1.infer;\ndeclare const systemExecutionOptionsQuerySchema: z$1.ZodObject<{\n providerId: z$1.ZodOptional;\n hostId: z$1.ZodOptional;\n environmentId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SystemExecutionOptionsQuery = z$1.infer;\n/** Omission preserves the existing behavior of reading the primary machine. */\ndeclare const systemUsageLimitsQuerySchema: z$1.ZodObject<{\n hostId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SystemUsageLimitsQuery = z$1.infer;\ndeclare const systemVoiceTranscriptionResponseSchema: z$1.ZodObject<{\n text: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemVoiceTranscriptionResponse = z$1.infer;\ndeclare const systemConfigResponseSchema: z$1.ZodObject<{\n generalSettings: z$1.ZodObject<{\n caffeinate: z$1.ZodBoolean;\n showKeyboardHints: z$1.ZodBoolean;\n showUnhandledProviderEvents: z$1.ZodBoolean;\n codexMemoryEnabled: z$1.ZodBoolean;\n claudeCodeMemoryEnabled: z$1.ZodBoolean;\n codexSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeSubagentsDisabled: z$1.ZodBoolean;\n claudeCodeWorkflowsDisabled: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n keybindings: z$1.ZodArray;\n desktopOnly: z$1.ZodBoolean;\n shortcut: z$1.ZodObject<{\n key: z$1.ZodString;\n mod: z$1.ZodBoolean;\n meta: z$1.ZodBoolean;\n control: z$1.ZodBoolean;\n alt: z$1.ZodBoolean;\n shift: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n when: z$1.ZodObject<{\n all: z$1.ZodArray>;\n none: z$1.ZodArray>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>>;\n defaultKeybindings: z$1.ZodArray;\n desktopOnly: z$1.ZodBoolean;\n shortcut: z$1.ZodObject<{\n key: z$1.ZodString;\n mod: z$1.ZodBoolean;\n meta: z$1.ZodBoolean;\n control: z$1.ZodBoolean;\n alt: z$1.ZodBoolean;\n shift: z$1.ZodBoolean;\n }, z$1.core.$strict>;\n when: z$1.ZodObject<{\n all: z$1.ZodArray>;\n none: z$1.ZodArray>;\n }, z$1.core.$strict>;\n }, z$1.core.$strict>>;\n keybindingOverrides: z$1.ZodArray;\n shortcut: z$1.ZodNullable>;\n }, z$1.core.$strict>>;\n experiments: z$1.ZodObject<{\n claudeCodeMockCliTraffic: z$1.ZodBoolean;\n plugins: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n appearance: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n }, z$1.core.$strip>;\n customThemes: z$1.ZodArray;\n pluginThemes: z$1.ZodArray;\n }, z$1.core.$strip>>;\n featureFlags: z$1.ZodObject<{\n placeholder: z$1.ZodBoolean;\n }, z$1.core.$strip>;\n hostDaemonPort: z$1.ZodNullable;\n primaryHostId: z$1.ZodNullable;\n primaryHostPlatform: z$1.ZodNullable>;\n voiceTranscriptionEnabled: z$1.ZodBoolean;\n dataDir: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemConfigResponse = z$1.infer;\ndeclare const systemAttentionResponseSchema: z$1.ZodObject<{\n hasAttention: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype SystemAttentionResponse = z$1.infer;\n/**\n * Theme catalog: the on-disk custom-theme directory plus the discovered custom\n * themes and the active palette. Drives `bb theme list` / `bb theme dir`.\n */\ndeclare const themeCatalogResponseSchema: z$1.ZodObject<{\n dir: z$1.ZodString;\n custom: z$1.ZodArray;\n plugins: z$1.ZodArray;\n }, z$1.core.$strip>>;\n active: z$1.ZodObject<{\n themeId: z$1.ZodString;\n customCss: z$1.ZodNullable;\n faviconColor: z$1.ZodEnum<{\n default: \"default\";\n red: \"red\";\n orange: \"orange\";\n yellow: \"yellow\";\n green: \"green\";\n teal: \"teal\";\n blue: \"blue\";\n purple: \"purple\";\n pink: \"pink\";\n }>;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>;\ntype ThemeCatalogResponse = z$1.infer;\ndeclare const systemVersionResponseSchema: z$1.ZodObject<{\n currentVersion: z$1.ZodString;\n latestVersion: z$1.ZodNullable;\n source: z$1.ZodLiteral<\"npm\">;\n updateAvailable: z$1.ZodBoolean;\n isDevelopment: z$1.ZodBoolean;\n upgradeCommand: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SystemVersionResponse = z$1.infer;\ndeclare const systemConfigReloadResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n}, z$1.core.$strip>;\ntype SystemConfigReloadResponse = z$1.infer;\n\ndeclare const terminalSessionSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodNullable;\n environmentId: z$1.ZodNullable;\n hostId: z$1.ZodString;\n title: z$1.ZodString;\n initialCwd: z$1.ZodString;\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n status: z$1.ZodEnum<{\n starting: \"starting\";\n disconnected: \"disconnected\";\n running: \"running\";\n exited: \"exited\";\n }>;\n exitCode: z$1.ZodNullable;\n closeReason: z$1.ZodNullable>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n lastUserInputAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TerminalSession = z$1.infer;\ndeclare const terminalListResponseSchema: z$1.ZodObject<{\n sessions: z$1.ZodArray;\n environmentId: z$1.ZodNullable;\n hostId: z$1.ZodString;\n title: z$1.ZodString;\n initialCwd: z$1.ZodString;\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n status: z$1.ZodEnum<{\n starting: \"starting\";\n disconnected: \"disconnected\";\n running: \"running\";\n exited: \"exited\";\n }>;\n exitCode: z$1.ZodNullable;\n closeReason: z$1.ZodNullable>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n lastUserInputAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype TerminalListResponse = z$1.infer;\ndeclare const createTerminalRequestSchema: z$1.ZodObject<{\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n start: z$1.ZodOptional;\n }, z$1.core.$strict>, z$1.ZodObject<{\n mode: z$1.ZodLiteral<\"command\">;\n command: z$1.ZodString;\n }, z$1.core.$strict>], \"mode\">>;\n target: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"environment\">;\n environmentId: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"host_path\">;\n hostId: z$1.ZodString;\n cwd: z$1.ZodNullable;\n }, z$1.core.$strict>], \"kind\">;\n title: z$1.ZodOptional;\n}, z$1.core.$strict>;\ntype CreateTerminalRequest = z$1.infer;\ndeclare const updateTerminalRequestSchema: z$1.ZodObject<{\n title: z$1.ZodString;\n}, z$1.core.$strict>;\ntype UpdateTerminalRequest = z$1.infer;\ndeclare const terminalInputRequestSchema: z$1.ZodObject<{\n dataBase64: z$1.ZodString;\n}, z$1.core.$strict>;\ntype TerminalInputRequest = z$1.infer;\ndeclare const terminalResizeRequestSchema: z$1.ZodObject<{\n cols: z$1.ZodNumber;\n rows: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype TerminalResizeRequest = z$1.infer;\ndeclare const terminalOutputQuerySchema: z$1.ZodObject<{\n sinceSeq: z$1.ZodOptional>;\n tailBytes: z$1.ZodOptional>;\n limitChunks: z$1.ZodOptional>;\n}, z$1.core.$strict>;\ntype TerminalOutputQuery = z$1.infer;\ndeclare const terminalOutputResponseSchema: z$1.ZodObject<{\n chunks: z$1.ZodArray>;\n nextSeq: z$1.ZodNumber;\n truncated: z$1.ZodBoolean;\n}, z$1.core.$strict>;\ntype TerminalOutputResponse = z$1.infer;\n\ndeclare const timelineRowStatusSchema: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n}>;\ntype TimelineRowStatus = z$1.infer;\ndeclare const timelineRowBaseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype TimelineRowBase = z$1.infer;\ndeclare const timelineConversationRowSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"conversation\">;\n text: z$1.ZodString;\n attachments: z$1.ZodNullable;\n localImagePaths: z$1.ZodArray;\n localFilePaths: z$1.ZodArray;\n }, z$1.core.$strip>>;\n role: z$1.ZodLiteral<\"user\">;\n initiator: z$1.ZodEnum<{\n user: \"user\";\n agent: \"agent\";\n system: \"system\";\n }>;\n senderThreadId: z$1.ZodNullable;\n actorHandle: z$1.ZodDefault>;\n systemMessageKind: z$1.ZodEnum<{\n \"ownership-assigned\": \"ownership-assigned\";\n \"ownership-removed\": \"ownership-removed\";\n \"child-needs-attention\": \"child-needs-attention\";\n \"child-completed\": \"child-completed\";\n \"child-failed\": \"child-failed\";\n \"child-interrupted\": \"child-interrupted\";\n \"child-outcome-batch\": \"child-outcome-batch\";\n unlabeled: \"unlabeled\";\n }>;\n systemMessageSubject: z$1.ZodNullable;\n threadId: z$1.ZodString;\n threadName: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread-batch\">;\n count: z$1.ZodNumber;\n }, z$1.core.$strip>], \"kind\">>;\n turnRequest: z$1.ZodObject<{\n kind: z$1.ZodEnum<{\n message: \"message\";\n steer: \"steer\";\n }>;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n accepted: \"accepted\";\n }>;\n }, z$1.core.$strip>;\n mentions: z$1.ZodArray, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"conversation\">;\n text: z$1.ZodString;\n attachments: z$1.ZodNullable;\n localImagePaths: z$1.ZodArray;\n localFilePaths: z$1.ZodArray;\n }, z$1.core.$strip>>;\n role: z$1.ZodLiteral<\"assistant\">;\n turnRequest: z$1.ZodNull;\n}, z$1.core.$strip>], \"role\">;\ntype TimelineConversationRow = z$1.infer;\ndeclare const timelineSystemRowSchema: z$1.ZodUnion;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n status: z$1.ZodNullable>;\n systemKind: z$1.ZodEnum<{\n error: \"error\";\n debug: \"debug\";\n reconnect: \"reconnect\";\n }>;\n}, z$1.core.$strip>, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n status: z$1.ZodNullable>;\n systemKind: z$1.ZodLiteral<\"operation\">;\n operationKind: z$1.ZodEnum<{\n generic: \"generic\";\n compaction: \"compaction\";\n \"thread-provisioning\": \"thread-provisioning\";\n \"thread-interrupted\": \"thread-interrupted\";\n \"provider-unhandled\": \"provider-unhandled\";\n warning: \"warning\";\n deprecation: \"deprecation\";\n }>;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"system\">;\n title: z$1.ZodString;\n detail: z$1.ZodNullable;\n systemKind: z$1.ZodLiteral<\"operation\">;\n operationKind: z$1.ZodLiteral<\"parent-change\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n parentChange: z$1.ZodObject<{\n action: z$1.ZodEnum<{\n assign: \"assign\";\n release: \"release\";\n transfer: \"transfer\";\n }>;\n previousParentThreadId: z$1.ZodNullable;\n previousParentThreadTitle: z$1.ZodNullable;\n nextParentThreadId: z$1.ZodNullable;\n nextParentThreadTitle: z$1.ZodNullable;\n }, z$1.core.$strip>;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>], \"operationKind\">]>;\ntype TimelineSystemRow = z$1.infer;\ninterface TimelineWorkRowBase extends TimelineRowBase {\n kind: \"work\";\n status: TimelineRowStatus;\n}\ndeclare const timelineCommandWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"command\">;\n callId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n source: z$1.ZodNullable;\n output: z$1.ZodString;\n exitCode: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n activityIntents: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"list_files\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype TimelineCommandWorkRow = z$1.infer;\ndeclare const timelineToolWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"tool\">;\n callId: z$1.ZodString;\n toolName: z$1.ZodString;\n toolArgs: z$1.ZodNullable>>>;\n output: z$1.ZodString;\n completedAt: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n activityIntents: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"list_files\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype TimelineToolWorkRow = z$1.infer;\ndeclare const timelineFileChangeWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"file-change\">;\n callId: z$1.ZodString;\n change: z$1.ZodObject<{\n path: z$1.ZodString;\n kind: z$1.ZodNullable;\n movePath: z$1.ZodNullable;\n diff: z$1.ZodNullable;\n diffStats: z$1.ZodObject<{\n added: z$1.ZodNumber;\n removed: z$1.ZodNumber;\n }, z$1.core.$strip>;\n }, z$1.core.$strip>;\n stdout: z$1.ZodNullable;\n stderr: z$1.ZodNullable;\n approvalStatus: z$1.ZodNullable>;\n}, z$1.core.$strip>;\ntype TimelineFileChangeWorkRow = z$1.infer;\ndeclare const timelineWebSearchWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"web-search\">;\n callId: z$1.ZodString;\n queries: z$1.ZodArray;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWebSearchWorkRow = z$1.infer;\ndeclare const timelineWebFetchWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"web-fetch\">;\n callId: z$1.ZodString;\n url: z$1.ZodString;\n prompt: z$1.ZodNullable;\n pattern: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWebFetchWorkRow = z$1.infer;\ndeclare const timelineImageViewWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"image-view\">;\n callId: z$1.ZodString;\n path: z$1.ZodString;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineImageViewWorkRow = z$1.infer;\ndeclare const timelineApprovalWorkRowSchema: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"approval\">;\n interactionId: z$1.ZodString;\n target: z$1.ZodObject<{\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n }, z$1.core.$strip>;\n approvalKind: z$1.ZodLiteral<\"file-edit\">;\n lifecycle: z$1.ZodEnum<{\n denied: \"denied\";\n waiting: \"waiting\";\n }>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"approval\">;\n interactionId: z$1.ZodString;\n target: z$1.ZodObject<{\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n }, z$1.core.$strip>;\n approvalKind: z$1.ZodLiteral<\"permission-grant\">;\n lifecycle: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n denied: \"denied\";\n resolving: \"resolving\";\n granted: \"granted\";\n }>;\n grantScope: z$1.ZodNullable>;\n statusReason: z$1.ZodNullable;\n}, z$1.core.$strip>], \"approvalKind\">;\ntype TimelineApprovalWorkRow = z$1.infer;\ndeclare const timelineQuestionWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"question\">;\n interactionId: z$1.ZodString;\n lifecycle: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n answered: \"answered\";\n }>;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n answers: z$1.ZodNullable;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n statusReason: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineQuestionWorkRow = z$1.infer;\ninterface TimelineDelegationWorkRow extends TimelineWorkRowBase {\n workKind: \"delegation\";\n callId: string;\n toolName: string;\n subagentType: string | null;\n description: string | null;\n output: string;\n completedAt: number | null;\n childRows: TimelineRow[];\n}\n/**\n * A provider background task — a dynamic workflow (Claude Code Workflow tool)\n * or a backgrounded shell command (Bash run_in_background), discriminated by\n * `taskType`. The row outlives its spawning turn: progress and terminal state\n * arrive via thread-scoped events folded into this single row. `workflow` is\n * the merged phase/agent tree, present only for workflows; null for shell\n * commands and for workflows the provider reported no progress records for\n * (degraded rendering falls back to description + summary).\n */\ndeclare const timelineWorkflowWorkRowSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n turnId: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype TimelineWorkflowWorkRow = z$1.infer;\ntype TimelineWorkRow = TimelineCommandWorkRow | TimelineToolWorkRow | TimelineFileChangeWorkRow | TimelineWebSearchWorkRow | TimelineWebFetchWorkRow | TimelineImageViewWorkRow | TimelineApprovalWorkRow | TimelineQuestionWorkRow | TimelineDelegationWorkRow | TimelineWorkflowWorkRow;\ninterface TimelineTurnRow extends TimelineRowBase {\n kind: \"turn\";\n turnId: string;\n status: TimelineRowStatus;\n summaryCount: number;\n completedAt: number | null;\n children: TimelineRow[] | null;\n}\ntype TimelineSourceRow = TimelineConversationRow | TimelineWorkRow | TimelineSystemRow;\ntype TimelineRow = TimelineSourceRow | TimelineTurnRow;\n\ndeclare const createThreadRequestSchema: z$1.ZodObject<{\n projectId: z$1.ZodString;\n providerId: z$1.ZodOptional;\n origin: z$1.ZodEnum<{\n plugin: \"plugin\";\n app: \"app\";\n cli: \"cli\";\n sdk: \"sdk\";\n }>;\n originPluginId: z$1.ZodOptional;\n visibility: z$1.ZodOptional>;\n title: z$1.ZodOptional;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n model: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n environment: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"reuse\">;\n environmentId: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"host\">;\n hostId: z$1.ZodOptional;\n workspace: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unmanaged\">;\n path: z$1.ZodNullable;\n branch: z$1.ZodOptional;\n name: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"new\">;\n baseBranch: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"managed-worktree\">;\n baseBranch: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"named\">;\n name: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"default\">;\n }, z$1.core.$strip>], \"kind\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"personal\">;\n }, z$1.core.$strip>], \"type\">;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"project-default\">;\n }, z$1.core.$strip>], \"type\">;\n parentThreadId: z$1.ZodOptional;\n sectionId: z$1.ZodOptional>;\n sourceThreadId: z$1.ZodOptional;\n sourceSeqEnd: z$1.ZodOptional;\n startedOnBehalfOf: z$1.ZodDefault;\n senderThreadId: z$1.ZodString;\n }, z$1.core.$strip>>>;\n originKind: z$1.ZodDefault>>;\n childOrigin: z$1.ZodDefault>>;\n}, z$1.core.$strip>;\ntype CreateThreadRequest = z$1.infer;\ndeclare const sendMessageRequestSchema: z$1.ZodObject<{\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n mode: z$1.ZodEnum<{\n steer: \"steer\";\n start: \"start\";\n auto: \"auto\";\n \"queue-if-active\": \"queue-if-active\";\n \"steer-if-active\": \"steer-if-active\";\n }>;\n senderThreadId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype SendMessageRequest = z$1.infer;\ndeclare const createQueuedMessageRequestSchema: z$1.ZodObject<{\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodOptional;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional, z$1.ZodLiteral<\"workspace-write\">]>, z$1.ZodTransform<\"auto\" | \"accept-edits\" | \"full\", \"auto\" | \"accept-edits\" | \"full\" | \"workspace-write\">>>;\n executionInputSources: z$1.ZodOptional>;\n serviceTier: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>;\n permissionMode: z$1.ZodOptional>;\n }, z$1.core.$strict>>;\n senderThreadId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype CreateQueuedMessageRequest = z$1.infer;\ndeclare const updateQueuedMessageRequestSchema: z$1.ZodObject<{\n expectedUpdatedAt: z$1.ZodNumber;\n input: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n}, z$1.core.$strip>;\ntype UpdateQueuedMessageRequest = z$1.infer;\ndeclare const sendQueuedMessageRequestSchema: z$1.ZodObject<{\n mode: z$1.ZodEnum<{\n steer: \"steer\";\n auto: \"auto\";\n }>;\n}, z$1.core.$strip>;\ntype SendQueuedMessageRequest = z$1.infer;\ndeclare const reorderQueuedMessageRequestSchema: z$1.ZodObject<{\n previousQueuedMessageId: z$1.ZodNullable;\n nextQueuedMessageId: z$1.ZodNullable;\n groupBoundaryQueuedMessageId: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ReorderQueuedMessageRequest = z$1.infer;\ndeclare const setQueuedMessageGroupBoundaryRequestSchema: z$1.ZodObject<{\n expectedGroupedPrefixQueuedMessageIds: z$1.ZodArray;\n groupBoundaryQueuedMessageId: z$1.ZodString;\n}, z$1.core.$strip>;\ntype SetQueuedMessageGroupBoundaryRequest = z$1.infer;\ndeclare const sendQueuedMessageResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n queuedMessage: z$1.ZodObject<{\n id: z$1.ZodString;\n content: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>;\n}, z$1.core.$strip>;\ntype SendQueuedMessageResponse = z$1.infer;\ndeclare const threadListResponseSchema: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n}, z$1.core.$strip>>;\ntype ThreadListResponse = z$1.infer;\ndeclare const threadSearchResponseSchema: z$1.ZodObject<{\n active: z$1.ZodObject<{\n total: z$1.ZodNumber;\n results: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>;\n matches: z$1.ZodArray;\n text: z$1.ZodString;\n highlightRanges: z$1.ZodArray>;\n sourceSeq: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>;\n archived: z$1.ZodObject<{\n total: z$1.ZodNumber;\n results: z$1.ZodArray;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n activity: z$1.ZodObject<{\n activeWorkflowCount: z$1.ZodNumber;\n activeBackgroundAgentCount: z$1.ZodNumber;\n activeBackgroundCommandCount: z$1.ZodNumber;\n activePlanModeCount: z$1.ZodNumber;\n activeGoalCount: z$1.ZodNumber;\n }, z$1.core.$strip>;\n pinSortKey: z$1.ZodNullable;\n hasPendingInteraction: z$1.ZodBoolean;\n environmentHostId: z$1.ZodNullable;\n environmentName: z$1.ZodNullable;\n environmentBranchName: z$1.ZodNullable;\n environmentWorkspaceDisplayKind: z$1.ZodEnum<{\n \"managed-worktree\": \"managed-worktree\";\n \"unmanaged-worktree\": \"unmanaged-worktree\";\n other: \"other\";\n }>;\n }, z$1.core.$strip>;\n matches: z$1.ZodArray;\n text: z$1.ZodString;\n highlightRanges: z$1.ZodArray>;\n sourceSeq: z$1.ZodNullable;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strict>;\n}, z$1.core.$strict>;\ntype ThreadSearchResponse = z$1.infer;\ndeclare const threadResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n environmentId: z$1.ZodNullable;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n canSpawnChild: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype ThreadResponse = z$1.infer;\ndeclare const threadGetQuerySchema: z$1.ZodObject<{\n include: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadGetQuery = z$1.infer;\ndeclare const threadWithIncludesResponseSchema: z$1.ZodObject<{\n id: z$1.ZodString;\n projectId: z$1.ZodString;\n environmentId: z$1.ZodNullable;\n providerId: z$1.ZodString;\n title: z$1.ZodNullable;\n titleFallback: z$1.ZodNullable;\n sectionId: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n }>;\n parentThreadId: z$1.ZodNullable;\n sourceThreadId: z$1.ZodNullable;\n originKind: z$1.ZodNullable>;\n childOrigin: z$1.ZodNullable>;\n originPluginId: z$1.ZodNullable;\n visibility: z$1.ZodEnum<{\n visible: \"visible\";\n hidden: \"hidden\";\n }>;\n archivedAt: z$1.ZodNullable;\n pinnedAt: z$1.ZodNullable;\n deletedAt: z$1.ZodNullable;\n lastReadAt: z$1.ZodNullable;\n latestAttentionAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n runtime: z$1.ZodObject<{\n displayStatus: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n stopping: \"stopping\";\n idle: \"idle\";\n starting: \"starting\";\n active: \"active\";\n \"host-reconnecting\": \"host-reconnecting\";\n \"waiting-for-host\": \"waiting-for-host\";\n }>;\n hostReconnectGraceExpiresAt: z$1.ZodNullable;\n }, z$1.core.$strip>;\n canSpawnChild: z$1.ZodBoolean;\n environment: z$1.ZodOptional;\n projectId: z$1.ZodString;\n hostId: z$1.ZodString;\n path: z$1.ZodNullable;\n managed: z$1.ZodBoolean;\n isGitRepo: z$1.ZodBoolean;\n isWorktree: z$1.ZodBoolean;\n workspaceProvisionType: z$1.ZodEnum<{\n unmanaged: \"unmanaged\";\n \"managed-worktree\": \"managed-worktree\";\n personal: \"personal\";\n }>;\n branchName: z$1.ZodNullable;\n baseBranch: z$1.ZodNullable;\n defaultBranch: z$1.ZodNullable;\n mergeBaseBranch: z$1.ZodNullable;\n status: z$1.ZodEnum<{\n error: \"error\";\n provisioning: \"provisioning\";\n ready: \"ready\";\n retiring: \"retiring\";\n destroying: \"destroying\";\n destroyed: \"destroyed\";\n }>;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>>>;\n host: z$1.ZodOptional;\n status: z$1.ZodEnum<{\n disconnected: \"disconnected\";\n connected: \"connected\";\n }>;\n lastSeenAt: z$1.ZodNullable;\n lastRejectedProtocolVersion: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n }, z$1.core.$strip>>>;\n}, z$1.core.$strip>;\ntype ThreadWithIncludesResponse = z$1.infer;\ndeclare const threadPendingInteractionsResponseSchema: z$1.ZodArray;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodString;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n origin: z$1.ZodOptional;\n providerId: z$1.ZodString;\n providerThreadId: z$1.ZodString;\n providerRequestId: z$1.ZodString;\n }, z$1.core.$strip>>;\n payload: z$1.ZodUnion;\n subject: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n itemId: z$1.ZodString;\n command: z$1.ZodString;\n cwd: z$1.ZodNullable;\n actions: z$1.ZodArray;\n command: z$1.ZodString;\n name: z$1.ZodString;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"listFiles\">;\n command: z$1.ZodString;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"search\">;\n command: z$1.ZodString;\n query: z$1.ZodNullable;\n path: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n type: z$1.ZodLiteral<\"unknown\">;\n command: z$1.ZodString;\n }, z$1.core.$strip>], \"type\">>;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"file_change\">;\n itemId: z$1.ZodString;\n writeScope: z$1.ZodNullable;\n sessionGrant: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"permission_grant\">;\n itemId: z$1.ZodString;\n toolName: z$1.ZodNullable;\n permissions: z$1.ZodObject<{\n network: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>;\n }, z$1.core.$strip>], \"kind\">;\n reason: z$1.ZodNullable;\n availableDecisions: z$1.ZodArray>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_question\">;\n questions: z$1.ZodArray;\n multiSelect: z$1.ZodBoolean;\n options: z$1.ZodOptional;\n }, z$1.core.$strip>>>;\n allowFreeText: z$1.ZodBoolean;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>;\n resolution: z$1.ZodNullable;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"allow_for_session\">;\n grantedPermissions: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n fileSystem: z$1.ZodNullable;\n write: z$1.ZodArray;\n }, z$1.core.$strip>>;\n }, z$1.core.$strict>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n decision: z$1.ZodLiteral<\"deny\">;\n }, z$1.core.$strip>], \"decision\">, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"user_answer\">;\n answers: z$1.ZodRecord;\n freeText: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>]>>;\n}, z$1.core.$strip>, z$1.ZodObject<{\n id: z$1.ZodString;\n threadId: z$1.ZodString;\n status: z$1.ZodEnum<{\n pending: \"pending\";\n interrupted: \"interrupted\";\n resolving: \"resolving\";\n resolved: \"resolved\";\n }>;\n statusReason: z$1.ZodNullable;\n createdAt: z$1.ZodNumber;\n expiresAt: z$1.ZodOptional>;\n resolvedAt: z$1.ZodNullable;\n turnId: z$1.ZodNullable;\n origin: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n rendererId: z$1.ZodString;\n }, z$1.core.$strip>;\n payload: z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n title: z$1.ZodString;\n data: z$1.ZodType>;\n }, z$1.core.$strip>;\n resolution: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>]>>;\ntype ThreadPendingInteractionsResponse = z$1.infer;\ndeclare const threadQueuedMessageListResponseSchema: z$1.ZodArray>;\n type: z$1.ZodLiteral<\"text\">;\n text: z$1.ZodString;\n mentions: z$1.ZodDefault, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"thread\">;\n threadId: z$1.ZodString;\n projectId: z$1.ZodOptional;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"project\">;\n projectId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"section\">;\n sectionId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"path\">;\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n entryKind: z$1.ZodEnum<{\n file: \"file\";\n directory: \"directory\";\n }>;\n path: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"command\">;\n trigger: z$1.ZodEnum<{\n \"/\": \"/\";\n }>;\n name: z$1.ZodString;\n source: z$1.ZodEnum<{\n command: \"command\";\n skill: \"skill\";\n }>;\n origin: z$1.ZodEnum<{\n user: \"user\";\n project: \"project\";\n builtin: \"builtin\";\n }>;\n label: z$1.ZodString;\n argumentHint: z$1.ZodNullable;\n }, z$1.core.$strip>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"plugin\">;\n pluginId: z$1.ZodString;\n icon: z$1.ZodOptional>;\n itemId: z$1.ZodString;\n label: z$1.ZodString;\n }, z$1.core.$strip>], \"kind\">>;\n }, z$1.core.$strip>>>;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"image\">;\n url: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localImage\">;\n path: z$1.ZodString;\n }, z$1.core.$strip>, z$1.ZodObject<{\n visibility: z$1.ZodOptional>;\n type: z$1.ZodLiteral<\"localFile\">;\n path: z$1.ZodString;\n name: z$1.ZodOptional;\n sizeBytes: z$1.ZodOptional;\n mimeType: z$1.ZodOptional;\n }, z$1.core.$strip>], \"type\">>;\n model: z$1.ZodString;\n reasoningLevel: z$1.ZodEnum<{\n none: \"none\";\n low: \"low\";\n medium: \"medium\";\n high: \"high\";\n xhigh: \"xhigh\";\n ultracode: \"ultracode\";\n max: \"max\";\n ultra: \"ultra\";\n }>;\n permissionMode: z$1.ZodEnum<{\n auto: \"auto\";\n \"accept-edits\": \"accept-edits\";\n full: \"full\";\n }>;\n serviceTier: z$1.ZodEnum<{\n default: \"default\";\n fast: \"fast\";\n }>;\n groupWithNext: z$1.ZodBoolean;\n createdAt: z$1.ZodNumber;\n updatedAt: z$1.ZodNumber;\n}, z$1.core.$strip>>;\ntype ThreadQueuedMessageListResponse = z$1.infer;\ndeclare const threadChildSummaryResponseSchema: z$1.ZodObject<{\n nonDeletedChildCount: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadChildSummaryResponse = z$1.infer;\ndeclare const deleteThreadRequestSchema: z$1.ZodObject<{\n childThreadsConfirmed: z$1.ZodBoolean;\n}, z$1.core.$strip>;\ntype DeleteThreadRequest = z$1.infer;\ndeclare const updateThreadRequestSchema: z$1.ZodObject<{\n title: z$1.ZodOptional>;\n sectionId: z$1.ZodOptional>;\n parentThreadId: z$1.ZodOptional>;\n model: z$1.ZodOptional>;\n reasoningLevel: z$1.ZodOptional>>;\n}, z$1.core.$strip>;\ntype UpdateThreadRequest = z$1.infer;\ndeclare const reorderPinnedThreadRequestSchema: z$1.ZodObject<{\n previousThreadId: z$1.ZodNullable;\n nextThreadId: z$1.ZodNullable;\n}, z$1.core.$strip>;\ntype ReorderPinnedThreadRequest = z$1.infer;\n/**\n * Requested placement for a thread opened in the app's split layout. Edge\n * placements add panes through the eighth pane; at the cap they replace the\n * focused pane. `replace` always replaces the focused pane.\n */\ndeclare const threadOpenSplitSchema: z$1.ZodEnum<{\n right: \"right\";\n down: \"down\";\n left: \"left\";\n top: \"top\";\n replace: \"replace\";\n}>;\ntype ThreadOpenSplit = z$1.infer;\n/** Optional secondary-panel file to open with a thread. */\ndeclare const threadOpenFileSchema: z$1.ZodObject<{\n source: z$1.ZodEnum<{\n workspace: \"workspace\";\n \"thread-storage\": \"thread-storage\";\n }>;\n path: z$1.ZodString;\n lineNumber: z$1.ZodNullable;\n}, z$1.core.$strict>;\ntype ThreadOpenFile = z$1.infer;\n/** Response for POST /threads/:id/open: how many connected clients received it. */\ndeclare const threadOpenResponseSchema: z$1.ZodObject<{\n delivered: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadOpenResponse = z$1.infer;\n/** Presentation action for one thread pane in each connected app window. */\ndeclare const threadPaneActionSchema: z$1.ZodEnum<{\n maximize: \"maximize\";\n restore: \"restore\";\n toggle: \"toggle\";\n}>;\ntype ThreadPaneAction = z$1.infer;\n/** Number of connected app clients that received the pane action. */\ndeclare const threadPaneActionResponseSchema: z$1.ZodObject<{\n delivered: z$1.ZodNumber;\n}, z$1.core.$strip>;\ntype ThreadPaneActionResponse = z$1.infer;\ndeclare const threadArchiveAllResponseSchema: z$1.ZodObject<{\n ok: z$1.ZodLiteral;\n archivedThreadIds: z$1.ZodArray;\n}, z$1.core.$strip>;\ntype ThreadArchiveAllResponse = z$1.infer;\ndeclare const threadListQuerySchema: z$1.ZodObject<{\n projectId: z$1.ZodOptional;\n parentThreadId: z$1.ZodOptional;\n sourceThreadId: z$1.ZodOptional;\n archived: z$1.ZodOptional>;\n sectionId: z$1.ZodOptional;\n unsectioned: z$1.ZodOptional>;\n hasParent: z$1.ZodOptional>;\n originKind: z$1.ZodOptional>;\n excludeSideChats: z$1.ZodOptional>;\n childOrigin: z$1.ZodOptional>;\n limit: z$1.ZodOptional;\n offset: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadListQuery = z$1.infer;\ndeclare const threadSearchQuerySchema: z$1.ZodObject<{\n query: z$1.ZodString;\n limitPerGroup: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadSearchQuery = z$1.infer;\ndeclare const threadTimelineQuerySchema: z$1.ZodObject<{\n includeNestedRows: z$1.ZodOptional>;\n segmentLimit: z$1.ZodOptional;\n beforeAnchorSeq: z$1.ZodOptional;\n beforeAnchorId: z$1.ZodOptional;\n summaryOnly: z$1.ZodOptional>;\n afterSequence: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadTimelineQuery = z$1.infer;\ndeclare const timelineTurnSummaryDetailsQuerySchema: z$1.ZodObject<{\n turnId: z$1.ZodString;\n sourceSeqStart: z$1.ZodString;\n sourceSeqEnd: z$1.ZodString;\n}, z$1.core.$strip>;\ntype TimelineTurnSummaryDetailsQuery = z$1.infer;\ndeclare const threadStorageFilesQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n}, z$1.core.$strip>;\ntype ThreadStorageFilesQuery = z$1.infer;\ndeclare const threadStoragePathsQuerySchema: z$1.ZodObject<{\n query: z$1.ZodOptional;\n limit: z$1.ZodOptional;\n includeFiles: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n includeDirectories: z$1.ZodEnum<{\n true: \"true\";\n false: \"false\";\n }>;\n}, z$1.core.$strip>;\ntype ThreadStoragePathsQuery = z$1.infer;\ndeclare const timelineTurnSummaryDetailsResponseSchema: z$1.ZodObject<{\n rows: z$1.ZodArray>>;\n}, z$1.core.$strip>;\ntype TimelineTurnSummaryDetailsResponse = z$1.infer;\ndeclare const threadTimelineResponseSchema: z$1.ZodObject<{\n rows: z$1.ZodArray>>;\n activePromptMode: z$1.ZodNullable;\n providerId: z$1.ZodEnum<{\n codex: \"codex\";\n \"claude-code\": \"claude-code\";\n }>;\n prompt: z$1.ZodString;\n }, z$1.core.$strict>>;\n activeThinking: z$1.ZodNullable>;\n activeWorkflow: z$1.ZodNullable;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n activeBackgroundCommands: z$1.ZodArray;\n sourceSeqStart: z$1.ZodNumber;\n sourceSeqEnd: z$1.ZodNumber;\n startedAt: z$1.ZodNumber;\n createdAt: z$1.ZodNumber;\n kind: z$1.ZodLiteral<\"work\">;\n status: z$1.ZodEnum<{\n error: \"error\";\n pending: \"pending\";\n completed: \"completed\";\n interrupted: \"interrupted\";\n }>;\n workKind: z$1.ZodLiteral<\"workflow\">;\n itemId: z$1.ZodString;\n taskType: z$1.ZodString;\n workflowName: z$1.ZodNullable;\n description: z$1.ZodString;\n taskStatus: z$1.ZodEnum<{\n pending: \"pending\";\n completed: \"completed\";\n running: \"running\";\n paused: \"paused\";\n failed: \"failed\";\n killed: \"killed\";\n stopped: \"stopped\";\n }>;\n workflow: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n agents: z$1.ZodArray;\n model: z$1.ZodString;\n attempt: z$1.ZodNumber;\n cached: z$1.ZodBoolean;\n lastProgressAt: z$1.ZodNumber;\n phaseIndex: z$1.ZodOptional;\n phaseTitle: z$1.ZodOptional;\n agentType: z$1.ZodOptional;\n isolation: z$1.ZodOptional;\n queuedAt: z$1.ZodOptional;\n startedAt: z$1.ZodOptional;\n lastToolName: z$1.ZodOptional;\n lastToolSummary: z$1.ZodOptional;\n promptPreview: z$1.ZodOptional;\n resultPreview: z$1.ZodOptional;\n error: z$1.ZodOptional;\n tokens: z$1.ZodOptional;\n toolCalls: z$1.ZodOptional;\n durationMs: z$1.ZodOptional;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n usage: z$1.ZodNullable>;\n summary: z$1.ZodNullable;\n error: z$1.ZodNullable;\n completedAt: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n pendingTodos: z$1.ZodNullable;\n }, z$1.core.$strip>>;\n }, z$1.core.$strip>>;\n goal: z$1.ZodNullable;\n tokenBudget: z$1.ZodNullable;\n tokensUsed: z$1.ZodNumber;\n timeUsedSeconds: z$1.ZodNumber;\n }, z$1.core.$strip>>;\n modelFallback: z$1.ZodNullable;\n message: z$1.ZodString;\n }, z$1.core.$strip>>;\n contextWindowUsage: z$1.ZodOptional>;\n timelinePage: z$1.ZodObject<{\n kind: z$1.ZodEnum<{\n latest: \"latest\";\n older: \"older\";\n }>;\n segmentLimit: z$1.ZodNumber;\n returnedSegmentCount: z$1.ZodNumber;\n hasOlderRows: z$1.ZodBoolean;\n olderCursor: z$1.ZodNullable>;\n }, z$1.core.$strict>;\n maxSeq: z$1.ZodNumber;\n delta: z$1.ZodOptional>>;\n rowOrder: z$1.ZodOptional>;\n }, z$1.core.$strip>>;\n}, z$1.core.$strip>;\ntype ThreadTimelineResponse = z$1.infer;\ndeclare const threadConversationOutlineResponseSchema: z$1.ZodObject<{\n items: z$1.ZodArray;\n preview: z$1.ZodString;\n attachmentSummary: z$1.ZodNullable>;\n }, z$1.core.$strict>>;\n maxSeq: z$1.ZodNumber;\n}, z$1.core.$strict>;\ntype ThreadConversationOutlineResponse = z$1.infer;\ndeclare const threadStorageFileListResponseSchema: z$1.ZodObject<{\n files: z$1.ZodArray>;\n truncated: z$1.ZodBoolean;\n storageRootPath: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ThreadStorageFileListResponse = z$1.infer;\ndeclare const threadStoragePathListResponseSchema: z$1.ZodObject<{\n paths: z$1.ZodArray;\n path: z$1.ZodString;\n name: z$1.ZodString;\n score: z$1.ZodNumber;\n positions: z$1.ZodArray;\n }, z$1.core.$strip>>;\n truncated: z$1.ZodBoolean;\n storageRootPath: z$1.ZodString;\n}, z$1.core.$strip>;\ntype ThreadStoragePathListResponse = z$1.infer;\n\ndeclare const threadTabsResponseSchema: z$1.ZodObject<{\n revision: z$1.ZodNumber;\n tabs: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"git-diff\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n actionId: z$1.ZodString;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"plugin-panel\">;\n paramsJson: z$1.ZodNullable;\n pluginId: z$1.ZodString;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n projectId: z$1.ZodNullable;\n source: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"working-tree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"head\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge-base\">;\n ref: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">;\n statusLabel: z$1.ZodNullable>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"host-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n isPinned: z$1.ZodBoolean;\n kind: z$1.ZodLiteral<\"thread-storage-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"browser\">;\n title: z$1.ZodNullable;\n url: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"new-tab\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"side-chat\">;\n sourceMessageText: z$1.ZodString;\n sourceSeqEnd: z$1.ZodNullable;\n threadId: z$1.ZodNullable;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"terminal\">;\n terminalId: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n}, z$1.core.$strict>;\ntype ThreadTabsResponse = z$1.infer;\ndeclare const updateThreadTabsRequestSchema: z$1.ZodObject<{\n expectedRevision: z$1.ZodNumber;\n tabs: z$1.ZodArray;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"git-diff\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n actionId: z$1.ZodString;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"plugin-panel\">;\n paramsJson: z$1.ZodNullable;\n pluginId: z$1.ZodString;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"workspace-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n projectId: z$1.ZodNullable;\n source: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"working-tree\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"head\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n kind: z$1.ZodLiteral<\"merge-base\">;\n ref: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">;\n statusLabel: z$1.ZodNullable>;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"host-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n isPinned: z$1.ZodBoolean;\n kind: z$1.ZodLiteral<\"thread-storage-file-preview\">;\n lineRange: z$1.ZodNullable>;\n path: z$1.ZodString;\n threadId: z$1.ZodNullable;\n }, z$1.core.$strict>, z$1.ZodObject<{\n environmentId: z$1.ZodNullable;\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"browser\">;\n title: z$1.ZodNullable;\n url: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"new-tab\">;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"side-chat\">;\n sourceMessageText: z$1.ZodString;\n sourceSeqEnd: z$1.ZodNullable;\n threadId: z$1.ZodNullable;\n title: z$1.ZodString;\n }, z$1.core.$strict>, z$1.ZodObject<{\n id: z$1.ZodString;\n kind: z$1.ZodLiteral<\"terminal\">;\n terminalId: z$1.ZodString;\n }, z$1.core.$strict>], \"kind\">>;\n}, z$1.core.$strict>;\ntype UpdateThreadTabsRequest = z$1.infer;\n\ninterface EnvironmentActionArgs {\n environmentId: string;\n}\ninterface EnvironmentGetArgs extends EnvironmentActionArgs {\n signal?: AbortSignal;\n}\ntype EnvironmentMergeBaseBranchUpdateValue = Exclude;\ntype EnvironmentNameUpdateValue = Exclude;\ninterface EnvironmentMergeBaseBranchUpdate {\n mergeBaseBranch: EnvironmentMergeBaseBranchUpdateValue;\n name?: EnvironmentNameUpdateValue;\n}\ninterface EnvironmentNameUpdate {\n mergeBaseBranch?: EnvironmentMergeBaseBranchUpdateValue;\n name: EnvironmentNameUpdateValue;\n}\ntype EnvironmentUpdateFields = EnvironmentMergeBaseBranchUpdate | EnvironmentNameUpdate;\ntype EnvironmentUpdateArgs = EnvironmentUpdateFields & {\n environmentId: string;\n};\ninterface EnvironmentStatusArgs extends EnvironmentStatusQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ntype EnvironmentDiffArgs = EnvironmentDiffQuery & {\n environmentId: string;\n signal?: AbortSignal;\n};\ntype EnvironmentDiffFileArgs = EnvironmentDiffFileQuery & {\n environmentId: string;\n signal?: AbortSignal;\n};\ninterface EnvironmentDiffBranchesArgs extends EnvironmentDiffBranchesQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ninterface EnvironmentCommitArgs {\n environmentId: string;\n}\ninterface EnvironmentSquashMergeArgs {\n environmentId: string;\n mergeBaseBranch: string;\n}\ninterface EnvironmentPullRequestMergeArgs {\n environmentId: string;\n method: PullRequestMergeMethod;\n}\ntype EnvironmentDiffPatchArgs = EnvironmentDiffPatchRequest & {\n environmentId: string;\n signal?: AbortSignal;\n};\ninterface EnvironmentPathsArgs extends EnvironmentPathsQuery {\n environmentId: string;\n signal?: AbortSignal;\n}\ntype EnvironmentArchiveThreadsResult = EnvironmentArchiveThreadsResponse;\ntype EnvironmentCommitResult = CommitActionResponse;\ntype EnvironmentDiffResult = EnvironmentDiffResponse;\ntype EnvironmentDiffBranchesResult = EnvironmentDiffBranchesResponse;\ntype EnvironmentDiffFileResult = EnvironmentDiffFileResponse;\ntype EnvironmentDiffFilesResult = EnvironmentDiffFilesResponse;\ntype EnvironmentDiffPatchResult = EnvironmentDiffPatchResponse;\ntype EnvironmentGetResult = Environment;\ntype EnvironmentMarkPullRequestDraftResult = PullRequestDraftActionResponse;\ntype EnvironmentMarkPullRequestReadyResult = PullRequestReadyActionResponse;\ntype EnvironmentMergePullRequestResult = PullRequestMergeActionResponse;\ntype EnvironmentPathsResult = WorkspacePathListResponse;\ntype EnvironmentPullRequestResult = EnvironmentPullRequestResponse;\ntype EnvironmentSquashMergeResult = SquashMergeActionResponse;\ntype EnvironmentStatusResult = EnvironmentStatusResponse;\ntype EnvironmentUpdateResult = Environment;\ninterface EnvironmentsArea {\n archiveThreads(args: EnvironmentActionArgs): Promise;\n commit(args: EnvironmentCommitArgs): Promise;\n diff(args: EnvironmentDiffArgs): Promise;\n diffBranches(args: EnvironmentDiffBranchesArgs): Promise;\n diffFile(args: EnvironmentDiffFileArgs): Promise;\n diffFiles(args: EnvironmentDiffArgs): Promise;\n diffPatch(args: EnvironmentDiffPatchArgs): Promise;\n get(args: EnvironmentGetArgs): Promise;\n pullRequest(args: EnvironmentGetArgs): Promise;\n markPullRequestDraft(args: EnvironmentActionArgs): Promise;\n markPullRequestReady(args: EnvironmentActionArgs): Promise;\n mergePullRequest(args: EnvironmentPullRequestMergeArgs): Promise;\n paths(args: EnvironmentPathsArgs): Promise;\n squashMerge(args: EnvironmentSquashMergeArgs): Promise;\n status(args: EnvironmentStatusArgs): Promise;\n update(args: EnvironmentUpdateArgs): Promise;\n}\n\n/**\n * Host file primitives. `hostId` may be omitted to target the server's\n * primary (local) host. `rootPath`, when set, confines the target beneath\n * that absolute root on the host (symlink-safe).\n */\ninterface FileReadArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n signal?: AbortSignal;\n}\ninterface FileWriteArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n content: string;\n /** Defaults to \"utf8\". */\n contentEncoding?: \"utf8\" | \"base64\";\n /** Defaults to false. */\n createParents?: boolean;\n /**\n * Optimistic-concurrency guard: omitted → unconditional write; a hash →\n * write only when the current content hashes to it (use `read().sha256`);\n * null → create-only. A failed guard resolves to the `conflict` outcome.\n */\n expectedSha256?: string | null;\n /** POSIX permission bits used when creating a file (for example 0o600). */\n mode?: number;\n}\ninterface FileListArgs {\n hostId?: string;\n path: string;\n query?: string;\n limit?: number;\n signal?: AbortSignal;\n}\ninterface PathListArgs extends FileListArgs {\n includeFiles: boolean;\n includeDirectories: boolean;\n}\ninterface FileMkdirArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n recursive?: boolean;\n}\ninterface FileMoveArgs {\n hostId?: string;\n sourcePath: string;\n destinationPath: string;\n rootPath?: string;\n}\ninterface FileRemoveArgs {\n hostId?: string;\n path: string;\n rootPath?: string;\n recursive?: boolean;\n}\ninterface FilePreviewArgs {\n hostId?: string;\n rootPath: string;\n signal?: AbortSignal;\n ttlMs?: number;\n}\ntype FileReadResult = HostFileReadResponse;\ntype FileWriteResult = HostFileWriteResponse;\ntype FileListResult = HostFileListResponse;\ntype PathListResult = HostPathListResponse;\ntype FileMkdirResult = HostMkdirResponse;\ntype FileMoveResult = HostMovePathResponse;\ntype FileRemoveResult = HostRemovePathResponse;\ntype FilePreviewResult = CreateFilePreviewResponse;\ninterface FilesArea {\n read(args: FileReadArgs): Promise;\n write(args: FileWriteArgs): Promise;\n list(args: FileListArgs): Promise;\n listPaths(args: PathListArgs): Promise;\n mkdir(args: FileMkdirArgs): Promise;\n move(args: FileMoveArgs): Promise;\n remove(args: FileRemoveArgs): Promise;\n createPreview(args: FilePreviewArgs): Promise;\n}\n\ninterface GuideRenderArgs {\n chapter?: string;\n}\ninterface GuideRenderResult {\n chapter?: string;\n content: string;\n}\ninterface GuideArea {\n render(args?: GuideRenderArgs): GuideRenderResult;\n}\n\ninterface HostGetArgs {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostDeleteArgs {\n hostId: string;\n}\ninterface HostUpdateArgs extends UpdateHostRequest {\n hostId: string;\n}\ninterface HostDirectoryArgs extends HostDirectoryQuery {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostCloneDefaultPathArgs extends HostCloneDefaultPathQuery {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostPathsExistArgs extends HostPathsExistRequest {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostPickFolderArgs extends HostPickFolderRequest {\n hostId: string;\n signal?: AbortSignal;\n}\ninterface HostProviderCliInstallArgs extends HostProviderCliInstallRequest {\n hostId: string;\n}\ninterface HostListArgs {\n signal?: AbortSignal;\n}\ntype HostCreateJoinCodeResult = CreateHostJoinCodeResponse;\ntype HostDeleteResult = {\n ok: true;\n};\ntype HostDirectoryResult = HostDirectoryListing;\ntype HostGetResult = Host;\ntype HostCloneDefaultPathResult = HostCloneDefaultPathResponse;\ntype HostProviderCliInstallResult = HostProviderCliInstallEvent[];\ntype HostListResult = Host[];\ntype HostPathsExistResult = HostPathsExistResponse;\ntype HostPickFolderResult = HostPickFolderResponse;\ntype HostProviderCliStatusResult = HostProviderCliStatusResponse;\ntype HostUpdateResult = Host;\ninterface HostsArea {\n createJoinCode(): Promise;\n delete(args: HostDeleteArgs): Promise;\n directory(args: HostDirectoryArgs): Promise;\n get(args: HostGetArgs): Promise;\n cloneDefaultPath(args: HostCloneDefaultPathArgs): Promise;\n installProviderCli(args: HostProviderCliInstallArgs): Promise;\n list(args?: HostListArgs): Promise;\n pathsExist(args: HostPathsExistArgs): Promise;\n pickFolder(args: HostPickFolderArgs): Promise;\n providerCliStatus(args: HostGetArgs): Promise;\n update(args: HostUpdateArgs): Promise;\n}\n\ninterface MemberAddArgs {\n handle: string;\n}\ninterface MemberRemoveArgs {\n handle: string;\n}\ntype MemberListResult = Member[];\ntype MemberAddResult = Member;\ntype MemberRemoveResult = {\n ok: true;\n};\ninterface MembersArea {\n add(args: MemberAddArgs): Promise;\n list(): Promise;\n remove(args: MemberRemoveArgs): Promise;\n}\n\ntype PresenceGetResult = PresenceSnapshotResponse;\ninterface PresenceArea {\n get(): Promise;\n}\n\ninterface ProjectListArgs {\n include?: ProjectListQuery[\"include\"];\n /** Include the singleton personal project. Defaults to false for compatibility. */\n includePersonal?: boolean;\n signal?: AbortSignal;\n}\ninterface ProjectCreateArgs extends CreateProjectRequest {\n}\ninterface ProjectGetArgs {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectUpdateArgs extends UpdateProjectRequest {\n projectId: string;\n}\ninterface ProjectDeleteArgs {\n projectId: string;\n}\ninterface ProjectReorderArgs extends ReorderProjectRequest {\n projectId: string;\n}\ninterface ProjectPromptHistoryArgs extends PromptHistoryQuery {\n projectId: string;\n signal?: AbortSignal;\n}\n/** Select one project workspace source, or omit both for the primary host. */\ntype ProjectWorkspaceRoutingArgs = {\n environmentId: string;\n hostId?: never;\n} | {\n environmentId?: never;\n hostId: string;\n} | {\n environmentId?: never;\n hostId?: never;\n};\ntype ProjectFilesArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectPathsArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectCommandsArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ntype ProjectFileContentArgs = ProjectWorkspaceRoutingArgs & Omit & {\n projectId: string;\n signal?: AbortSignal;\n};\ninterface ProjectBranchesArgs extends ProjectBranchesQuery {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectDefaultExecutionOptionsArgs {\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectAttachmentFileLike {\n arrayBuffer(): Promise;\n readonly name: string;\n readonly type?: string;\n}\ninterface ProjectAttachmentUploadArgsBase {\n /** MIME override. Omit to use the File/Blob type, when available. */\n mimeType?: string;\n projectId: string;\n}\n/**\n * Upload bytes owned by this SDK client. A bare Blob/byte buffer needs an\n * explicit filename; File-like values can supply their own name.\n */\ntype ProjectAttachmentUploadArgs = ProjectAttachmentUploadArgsBase & ({\n clientFile: ProjectAttachmentFileLike;\n filename?: string;\n} | {\n clientFile: ArrayBuffer | Blob | Uint8Array;\n filename: string;\n});\ninterface ProjectAttachmentReadArgs {\n path: string;\n projectId: string;\n signal?: AbortSignal;\n}\ninterface ProjectAttachmentCopyArgs extends CopyProjectAttachmentsRequest {\n projectId: string;\n}\ntype ProjectSourceAddArgs = CreateProjectSourceRequest & {\n projectId: string;\n};\ninterface ProjectSourceUpdateArgs extends UpdateProjectSourceRequest {\n projectId: string;\n sourceId: string;\n}\ninterface ProjectSourceDeleteArgs {\n projectId: string;\n sourceId: string;\n}\ntype ProjectBranchesResult = ProjectBranchesResponse;\ninterface ProjectAttachmentReadResult {\n bytes: Uint8Array;\n mimeType: string;\n sizeBytes: number;\n}\ntype ProjectAttachmentUploadResult = UploadedPromptAttachment;\ntype ProjectCommandsResult = CommandListResponse;\ntype ProjectCreateResult = ProjectResponse;\ntype ProjectDefaultExecutionOptionsResult = ProjectExecutionDefaults | null;\ntype ProjectDeleteResult = {\n ok: true;\n};\ninterface ProjectFileContentResult {\n /** UTF-8 text or base64, as selected by `contentEncoding`. */\n content: string;\n contentEncoding: \"utf8\" | \"base64\";\n mimeType: string;\n sizeBytes: number;\n}\ntype ProjectFilesResult = WorkspaceFileListResponse;\ntype ProjectGetResult = ProjectResponse;\ntype ProjectListResult = ProjectResponse[] | ProjectWithThreadsResponse[];\ntype ProjectPathsResult = WorkspacePathListResponse;\ntype ProjectPromptHistoryResult = PromptHistoryResponse;\ntype ProjectReorderResult = ProjectResponse[];\ntype ProjectSourceAddResult = ProjectSource;\ntype ProjectSourceDeleteResult = {\n ok: true;\n};\ntype ProjectSourceUpdateResult = ProjectSource;\ntype ProjectUpdateResult = ProjectResponse;\ninterface ProjectSourcesArea {\n add(args: ProjectSourceAddArgs): Promise;\n delete(args: ProjectSourceDeleteArgs): Promise;\n update(args: ProjectSourceUpdateArgs): Promise;\n}\ninterface ProjectAttachmentsArea {\n copy(args: ProjectAttachmentCopyArgs): Promise;\n read(args: ProjectAttachmentReadArgs): Promise;\n upload(args: ProjectAttachmentUploadArgs): Promise;\n}\ninterface ProjectsArea {\n attachments: ProjectAttachmentsArea;\n branches(args: ProjectBranchesArgs): Promise;\n commands(args: ProjectCommandsArgs): Promise;\n create(args: ProjectCreateArgs): Promise;\n defaultExecutionOptions(args: ProjectDefaultExecutionOptionsArgs): Promise;\n delete(args: ProjectDeleteArgs): Promise;\n fileContent(args: ProjectFileContentArgs): Promise;\n files(args: ProjectFilesArgs): Promise;\n get(args: ProjectGetArgs): Promise;\n list(args?: ProjectListArgs): Promise;\n paths(args: ProjectPathsArgs): Promise;\n promptHistory(args: ProjectPromptHistoryArgs): Promise;\n reorder(args: ProjectReorderArgs): Promise;\n sources: ProjectSourcesArea;\n update(args: ProjectUpdateArgs): Promise;\n}\n\n/** Select exactly one provider-discovery host source, or omit both for primary. */\ntype ProviderHostRoutingArgs = {\n environmentId: string;\n hostId?: never;\n} | {\n environmentId?: never;\n hostId: string;\n} | {\n environmentId?: never;\n hostId?: never;\n};\ntype ProviderListArgs = ProviderHostRoutingArgs & {\n signal?: AbortSignal;\n};\ntype ProviderModelsArgs = ProviderHostRoutingArgs & {\n providerId?: string;\n signal?: AbortSignal;\n};\ntype ProviderListResult = ProviderInfo[];\ntype ProviderModelsResult = SystemExecutionOptionsResponse;\ninterface ProvidersArea {\n /** List providers on the environment host, explicit host, or primary host. */\n list(args?: ProviderListArgs): Promise;\n /** List models on the environment host, explicit host, or primary host. */\n models(args?: ProviderModelsArgs): Promise;\n}\n\ninterface PluginIdArgs {\n pluginId: string;\n}\n/** Install directly from a path:, git:, npm:, or builtin: source spec. */\ninterface PluginInstallArgs {\n source: string;\n}\n/** Install an entry from BB's official catalog. */\ninterface PluginCatalogInstallArgs {\n entryId: string;\n}\ninterface PluginReloadArgs {\n pluginId?: string;\n}\ninterface PluginSettingsUpdateArgs extends PluginIdArgs {\n values: Record;\n}\ninterface PluginTokenArgs extends PluginIdArgs {\n rotate?: boolean;\n}\ninterface PluginCheckUpdatesArgs {\n pluginId?: string;\n signal?: AbortSignal;\n}\ninterface PluginRpcArgs extends PluginIdArgs {\n input?: JsonValue;\n method: string;\n outputSchema: z$1.ZodType;\n}\ninterface PluginCatalogSearchArgs {\n query: string;\n signal?: AbortSignal;\n}\ninterface PluginCatalogStatusArgs {\n signal?: AbortSignal;\n}\ninterface PluginGetSettingsArgs extends PluginIdArgs {\n signal?: AbortSignal;\n}\ninterface PluginGetSourceArgs extends PluginIdArgs {\n signal?: AbortSignal;\n}\ninterface PluginListArgs {\n signal?: AbortSignal;\n}\ninterface PluginListUpdateResultsArgs {\n signal?: AbortSignal;\n}\ntype PluginDisableResult = InstalledPlugin;\ntype PluginEnableResult = InstalledPlugin;\ntype PluginGetSettingsResult = PluginSettingsResponse;\ntype PluginInstallResult = InstalledPlugin;\ntype PluginListResult = PluginListResponse;\ntype PluginReloadResult = PluginReloadResponse;\ntype PluginRemoveResult = PluginRemoveResponse;\ntype PluginTokenResult = PluginTokenResponse;\ntype PluginUpdateSettingsResult = PluginSettingsResponse;\ntype PluginGetSourceResult = PluginSourceDetail;\ntype PluginCheckUpdatesResult = PluginUpdateCheckEntry[];\ntype PluginApplyUpdateResult = PluginApplyUpdateResult$1;\ntype PluginCatalogStatusResult = PluginCatalogStatus;\ntype PluginCatalogSearchResult = PluginCatalogSearchResult$1[];\ninterface PluginCatalogArea {\n install(args: PluginCatalogInstallArgs): Promise;\n search(args: PluginCatalogSearchArgs): Promise;\n status(args?: PluginCatalogStatusArgs): Promise;\n}\ninterface PluginsArea {\n applyUpdate(args: PluginIdArgs): Promise;\n callRpc(args: PluginRpcArgs): Promise;\n checkUpdates(args?: PluginCheckUpdatesArgs): Promise;\n catalog: PluginCatalogArea;\n disable(args: PluginIdArgs): Promise;\n enable(args: PluginIdArgs): Promise;\n getSettings(args: PluginGetSettingsArgs): Promise;\n getSource(args: PluginGetSourceArgs): Promise;\n install(args: PluginInstallArgs): Promise;\n list(args?: PluginListArgs): Promise;\n listUpdateResults(args?: PluginListUpdateResultsArgs): Promise;\n reload(args?: PluginReloadArgs): Promise;\n remove(args: PluginIdArgs): Promise;\n token(args: PluginTokenArgs): Promise;\n updateSettings(args: PluginSettingsUpdateArgs): Promise;\n}\n\ntype BbRealtimeUnsubscribe = () => void;\ntype BbRealtimeEventName = \"thread:changed\" | \"project:changed\" | \"environment:changed\" | \"host:changed\" | \"system:changed\" | \"system:config-changed\" | \"realtime:connection\";\ntype ThreadRealtimeEvent = Extract;\ntype ProjectRealtimeEvent = Extract;\ntype EnvironmentRealtimeEvent = Extract;\ntype HostRealtimeEvent = Extract;\ntype SystemRealtimeEvent = Extract;\ntype BbRealtimeConnectionState = \"connecting\" | \"connected\" | \"disconnected\";\ninterface BbRealtimeConnectionEvent {\n reconnectDelayMs: number | null;\n reconnected: boolean;\n state: BbRealtimeConnectionState;\n}\n/**\n * Entity-changed events are delivered as one shared object to every matching\n * listener; their payload types are readonly so a listener cannot mutate what\n * the next listener receives.\n */\ninterface BbRealtimeEventMap {\n \"thread:changed\": ThreadRealtimeEvent;\n \"project:changed\": ProjectRealtimeEvent;\n \"environment:changed\": EnvironmentRealtimeEvent;\n \"host:changed\": HostRealtimeEvent;\n \"system:changed\": SystemRealtimeEvent;\n \"system:config-changed\": SystemRealtimeEvent;\n \"realtime:connection\": BbRealtimeConnectionEvent;\n}\ntype BbRealtimeCallback = (event: BbRealtimeEventMap[TEventName]) => void;\ninterface ThreadRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"thread:changed\">;\n event: \"thread:changed\";\n threadId?: string;\n}\ninterface ProjectRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"project:changed\">;\n event: \"project:changed\";\n projectId?: string;\n}\ninterface EnvironmentRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"environment:changed\">;\n environmentId?: string;\n event: \"environment:changed\";\n}\ninterface HostRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"host:changed\">;\n event: \"host:changed\";\n hostId?: string;\n}\ninterface SystemRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"system:changed\">;\n event: \"system:changed\";\n}\ninterface SystemConfigRealtimeSubscribeArgs {\n callback: BbRealtimeCallback<\"system:config-changed\">;\n event: \"system:config-changed\";\n}\n/**\n * Connection listeners are pure observers — they never open or hold the\n * socket. A listener registered while a socket already exists receives the\n * latest connection event as a snapshot on the next microtask, so a status\n * UI mounted after connect still learns the current state.\n */\ninterface RealtimeConnectionSubscribeArgs {\n callback: BbRealtimeCallback<\"realtime:connection\">;\n event: \"realtime:connection\";\n}\ntype BbRealtimeSubscribeArgsUnion = ThreadRealtimeSubscribeArgs | ProjectRealtimeSubscribeArgs | EnvironmentRealtimeSubscribeArgs | HostRealtimeSubscribeArgs | SystemRealtimeSubscribeArgs | SystemConfigRealtimeSubscribeArgs | RealtimeConnectionSubscribeArgs;\ntype BbRealtimeSubscribeArgs = Extract;\ninterface BbRealtime {\n subscribe(args: BbRealtimeSubscribeArgs): BbRealtimeUnsubscribe;\n}\n\ninterface StatusGetArgs {\n projectId?: string;\n signal?: AbortSignal;\n threadId?: string;\n}\ninterface StatusThreadSummary {\n environmentId: string | null;\n id: string;\n parentThreadId: string | null;\n pinnedAt: number | null;\n projectId: string;\n status: ThreadStatus;\n title: string | null;\n}\ntype StatusProject = ProjectResponse;\ntype StatusChildThreads = ThreadListResponse;\ninterface StatusResult {\n childThreads: StatusChildThreads | null;\n pendingTodos: ThreadTimelinePendingTodos | null;\n project: StatusProject | null;\n thread: StatusThreadSummary | null;\n}\ninterface StatusArea {\n get(args?: StatusGetArgs): Promise;\n}\n\ntype ThemeGetResult = AppTheme;\ntype ThemeCatalogResult = ThemeCatalogResponse;\ntype ThemeSetInput = AppThemeSelection;\ntype ThemeSetResult = AppTheme;\ninterface ThemeCatalogArgs {\n signal?: AbortSignal;\n}\ninterface ThemeGetArgs {\n signal?: AbortSignal;\n}\ninterface ThemeArea {\n /** The active app palette, resolved server-side (built-in id or custom CSS). */\n get(args?: ThemeGetArgs): Promise;\n /** The custom-theme directory plus discovered themes and the active palette. */\n catalog(args?: ThemeCatalogArgs): Promise;\n /** Set the complete app appearance selection in one request. */\n set(selection: ThemeSetInput): Promise;\n /**\n * Activate a palette by id while preserving the active favicon color. This\n * compatibility shorthand reads the active appearance before writing the\n * complete selection; prefer the object form when both values are known.\n */\n set(themeId: string): Promise;\n}\n\ninterface SystemAttentionArgs {\n signal?: AbortSignal;\n}\ninterface SystemConfigArgs {\n signal?: AbortSignal;\n}\ninterface SystemExecutionOptionsArgs extends SystemExecutionOptionsQuery {\n signal?: AbortSignal;\n}\ninterface SystemUsageLimitsArgs extends SystemUsageLimitsQuery {\n signal?: AbortSignal;\n}\ninterface SystemVersionArgs {\n force?: boolean;\n signal?: AbortSignal;\n}\ninterface SystemVoiceTranscriptionArgs {\n file: Blob;\n prompt?: string;\n signal?: AbortSignal;\n}\ntype SystemAttentionResult = SystemAttentionResponse;\ntype SystemConfigResult = SystemConfigResponse;\ntype SystemExecutionOptionsResult = SystemExecutionOptionsResponse;\ntype SystemReloadConfigResult = SystemConfigReloadResponse;\ntype SystemVoiceTranscriptionResult = SystemVoiceTranscriptionResponse;\ntype SystemUpdateExperimentsResult = Experiments;\ntype SystemUpdateGeneralSettingsResult = AppSettings;\ntype SystemUpdateKeyboardSettingsResult = AppKeybindingOverrides;\ntype SystemUsageLimitsResult = ProviderUsageResponse;\ntype SystemVersionResult = SystemVersionResponse;\ninterface SystemArea {\n attention(args?: SystemAttentionArgs): Promise;\n config(args?: SystemConfigArgs): Promise;\n executionOptions(args?: SystemExecutionOptionsArgs): Promise;\n reloadConfig(): Promise;\n transcribeVoice(args: SystemVoiceTranscriptionArgs): Promise;\n updateExperiments(args: Experiments): Promise;\n updateGeneralSettings(args: AppSettings): Promise;\n updateKeyboardSettings(args: AppKeybindingOverrides): Promise;\n usageLimits(args?: SystemUsageLimitsArgs): Promise;\n version(args?: SystemVersionArgs): Promise;\n}\n\ninterface TerminalThreadScope {\n cwd?: never;\n environmentId?: never;\n hostId?: never;\n kind: \"thread\";\n threadId: string;\n}\ninterface TerminalEnvironmentScope {\n environmentId: string;\n cwd?: never;\n hostId?: never;\n kind: \"environment\";\n threadId?: never;\n}\ninterface TerminalHostPathListScope {\n /** Optional exact initial working-directory filter on the selected host. */\n cwd?: string;\n environmentId?: never;\n hostId: string;\n kind: \"host_path\";\n threadId?: never;\n}\ninterface TerminalHostPathCreateScope {\n /** Null starts in the selected host's home directory. */\n cwd: string | null;\n environmentId?: never;\n hostId: string;\n kind: \"host_path\";\n threadId?: never;\n}\ntype TerminalListScope = TerminalThreadScope | TerminalEnvironmentScope | TerminalHostPathListScope;\ntype TerminalCreateScope = TerminalThreadScope | TerminalEnvironmentScope | TerminalHostPathCreateScope;\ninterface TerminalListArgs {\n signal?: AbortSignal;\n scope: TerminalListScope;\n}\ninterface TerminalCreateArgs {\n cols: number;\n rows: number;\n scope: TerminalCreateScope;\n start?: CreateTerminalRequest[\"start\"];\n title?: string;\n}\ninterface TerminalTargetArgs {\n terminalId: string;\n}\ninterface TerminalGetArgs extends TerminalTargetArgs {\n signal?: AbortSignal;\n}\ninterface TerminalRenameArgs extends TerminalTargetArgs {\n title: UpdateTerminalRequest[\"title\"];\n}\ninterface TerminalCloseArgs extends TerminalTargetArgs {\n mode: \"force\" | \"if-clean\";\n}\ninterface TerminalInputArgs extends TerminalTargetArgs {\n dataBase64: TerminalInputRequest[\"dataBase64\"];\n}\ninterface TerminalResizeArgs extends TerminalTargetArgs {\n cols: TerminalResizeRequest[\"cols\"];\n rows: TerminalResizeRequest[\"rows\"];\n}\ninterface TerminalOutputArgs extends TerminalTargetArgs {\n limitChunks?: TerminalOutputQuery[\"limitChunks\"];\n signal?: AbortSignal;\n sinceSeq?: TerminalOutputQuery[\"sinceSeq\"];\n tailBytes?: TerminalOutputQuery[\"tailBytes\"];\n}\ntype TerminalRestartArgs = TerminalTargetArgs;\ntype TerminalListResult = TerminalListResponse;\ntype TerminalCreateResult = TerminalSession;\ntype TerminalGetResult = TerminalSession;\ntype TerminalRenameResult = TerminalSession;\ntype TerminalCloseResult = TerminalSession;\ntype TerminalInputResult = TerminalSession;\ntype TerminalResizeResult = TerminalSession;\ntype TerminalOutputResult = TerminalOutputResponse;\ntype TerminalRestartResult = TerminalSession;\ninterface TerminalsArea {\n close(args: TerminalCloseArgs): Promise;\n create(args: TerminalCreateArgs): Promise;\n get(args: TerminalGetArgs): Promise;\n input(args: TerminalInputArgs): Promise;\n list(args: TerminalListArgs): Promise;\n output(args: TerminalOutputArgs): Promise;\n rename(args: TerminalRenameArgs): Promise;\n /**\n * Replace a terminal with a shell at the same scope, size, and title.\n * The original command is not replayed because terminal sessions do not\n * persist launch commands. The replacement has a new terminal ID.\n */\n restart(args: TerminalRestartArgs): Promise;\n resize(args: TerminalResizeArgs): Promise;\n}\n\ninterface ThreadListArgs {\n archived?: boolean;\n excludeSideChats?: boolean;\n sectionId?: string;\n hasParent?: boolean;\n limit?: number;\n offset?: number;\n originKind?: ThreadListQuery[\"originKind\"];\n parentThreadId?: string;\n projectId?: string;\n signal?: AbortSignal;\n sourceThreadId?: string;\n unsectioned?: boolean;\n}\ninterface ThreadSearchArgs extends ThreadSearchQuery {\n signal?: AbortSignal;\n}\ninterface ThreadGetArgs {\n include?: ThreadGetQuery[\"include\"];\n signal?: AbortSignal;\n threadId: string;\n}\ntype ThreadGetResult = ThreadResponse | ThreadWithIncludesResponse;\ntype ThreadListResult = ThreadListResponse;\ntype ThreadSearchResult = ThreadSearchResponse;\ninterface ThreadOutputResponse {\n output: string | null;\n}\ntype ThreadMutationResult = ThreadResponse;\ntype ThreadSpawnResult = ThreadResponse;\ntype ThreadInteractionGetResult = PendingInteraction;\ntype ThreadInteractionListResult = ThreadPendingInteractionsResponse;\ntype ThreadInteractionResolveResult = PendingInteraction;\ntype ThreadInteractionRespondResult = PendingInteraction;\ntype ThreadInteractionCancelResult = PendingInteraction;\ntype ThreadEventsListResult = ThreadEventRow[];\ntype ThreadEventWaitResult = ThreadEventRow | null;\ntype ThreadTimelineResult = ThreadTimelineResponse;\ntype ThreadArchiveResult = ThreadArchiveAllResponse;\ntype ThreadOpenResult = ThreadOpenResponse;\ntype ThreadPaneActionResult = ThreadPaneActionResponse;\ntype ThreadDeleteResult = {\n ok: true;\n};\ntype ThreadSendResult = {\n ok: true;\n};\ntype ThreadStopResult = {\n ok: true;\n};\ntype ThreadUnarchiveResult = {\n ok: true;\n};\ntype ThreadArchiveAllResult = ThreadArchiveAllResponse;\ntype ThreadReadStateResult = ThreadResponse;\ntype ThreadPinOrderResult = ThreadListResponse;\ntype ThreadPromptHistoryResult = PromptHistoryResponse;\ntype ThreadQueuedMessagesResult = ThreadQueuedMessageListResponse;\ntype ThreadQueuedMessageCreateResult = ThreadQueuedMessage;\ntype ThreadQueuedMessageUpdateResult = ThreadQueuedMessage;\ntype ThreadQueuedMessageDeleteResult = {\n ok: true;\n};\ntype ThreadQueuedMessageReorderResult = ThreadQueuedMessageListResponse;\ntype ThreadQueuedMessageSendResult = SendQueuedMessageResponse;\ntype ThreadQueuedMessageGroupBoundaryResult = ThreadQueuedMessageListResponse;\ntype ThreadTabsResult = ThreadTabsResponse;\ntype ThreadTabsUpdateResult = ThreadTabsResponse;\ntype ThreadStorageFilesResult = ThreadStorageFileListResponse;\ntype ThreadStoragePathsResult = ThreadStoragePathListResponse;\ntype ThreadChildSummaryResult = ThreadChildSummaryResponse;\ntype ThreadDefaultExecutionOptionsResult = ResolvedThreadExecutionOptions | null;\ntype ThreadConversationOutlineResult = ThreadConversationOutlineResponse;\ntype ThreadTimelineTurnSummaryDetailsResult = TimelineTurnSummaryDetailsResponse;\ninterface ThreadSpawnBaseArgs extends Omit {\n childOrigin?: CreateThreadRequest[\"childOrigin\"];\n origin?: CreateThreadRequest[\"origin\"];\n originKind?: CreateThreadRequest[\"originKind\"];\n startedOnBehalfOf?: CreateThreadRequest[\"startedOnBehalfOf\"];\n}\ntype ThreadSpawnArgs = ThreadSpawnBaseArgs & ({\n input: CreateThreadRequest[\"input\"];\n prompt?: never;\n} | {\n input?: never;\n prompt: string;\n});\ninterface ThreadUpdateArgs extends UpdateThreadRequest {\n threadId: string;\n}\ninterface ThreadDeleteArgs extends DeleteThreadRequest {\n threadId: string;\n}\ninterface ThreadSendArgs extends SendMessageRequest {\n threadId: string;\n}\ninterface ThreadActionArgs {\n threadId: string;\n}\ninterface ThreadStatusArgs extends ThreadActionArgs {\n signal?: AbortSignal;\n}\ninterface ThreadPromptHistoryArgs extends PromptHistoryQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadPinOrderArgs extends ReorderPinnedThreadRequest {\n threadId: string;\n}\ninterface ThreadQueuedMessageArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadQueuedMessageCreateArgs extends CreateQueuedMessageRequest {\n threadId: string;\n}\ninterface ThreadQueuedMessageUpdateArgs extends ThreadQueuedMessageTargetArgs, UpdateQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageTargetArgs {\n queuedMessageId: string;\n threadId: string;\n}\ninterface ThreadQueuedMessageSendArgs extends ThreadQueuedMessageTargetArgs, SendQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageReorderArgs extends ThreadQueuedMessageTargetArgs, ReorderQueuedMessageRequest {\n}\ninterface ThreadQueuedMessageGroupBoundaryArgs extends SetQueuedMessageGroupBoundaryRequest {\n threadId: string;\n}\ninterface ThreadStorageFilesArgs extends ThreadStorageFilesQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadStoragePathsArgs extends ThreadStoragePathsQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadTimelineTurnSummaryDetailsArgs extends TimelineTurnSummaryDetailsQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadTabsUpdateArgs extends UpdateThreadTabsRequest {\n threadId: string;\n}\ninterface ThreadOpenArgs {\n threadId: string;\n split?: ThreadOpenSplit;\n file: ThreadOpenFile | null;\n}\ninterface ThreadPaneActionArgs {\n action: ThreadPaneAction;\n threadId: string;\n}\ninterface ThreadEventsListArgs {\n afterSeq?: string;\n limit?: string;\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadEventWaitArgs {\n afterSeq?: string;\n signal?: AbortSignal;\n threadId: string;\n type: string;\n waitMs: string;\n}\ninterface ThreadTimelineArgs extends ThreadTimelineQuery {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadOutputArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadInteractionListArgs {\n signal?: AbortSignal;\n threadId: string;\n}\ninterface ThreadInteractionTargetArgs {\n interactionId: string;\n threadId: string;\n}\ninterface ThreadInteractionGetArgs extends ThreadInteractionTargetArgs {\n signal?: AbortSignal;\n}\ninterface ThreadInteractionResolveArgs extends ThreadInteractionTargetArgs {\n resolution: PendingInteractionResolution;\n}\ninterface ThreadInteractionRespondArgs extends ThreadInteractionTargetArgs {\n value: JsonValue;\n}\ntype ThreadWaitTarget = {\n kind: \"status\";\n status: ThreadStatus;\n} | {\n kind: \"event\";\n eventType: string;\n};\ninterface ThreadWaitArgs {\n event?: string;\n pollIntervalMs?: number;\n signal?: AbortSignal;\n status?: ThreadStatus;\n threadId: string;\n timeoutMs?: number;\n}\ntype ThreadWaitResult = {\n event: NonNullable;\n matched: true;\n target: Extract;\n threadId: string;\n} | {\n matched: true;\n target: Extract;\n thread: ThreadGetResult;\n threadId: string;\n};\ninterface ThreadInteractionsArea {\n cancel(args: ThreadInteractionTargetArgs): Promise;\n get(args: ThreadInteractionGetArgs): Promise;\n list(args: ThreadInteractionListArgs): Promise;\n resolve(args: ThreadInteractionResolveArgs): Promise;\n respond(args: ThreadInteractionRespondArgs): Promise;\n}\ninterface ThreadEventsArea {\n list(args: ThreadEventsListArgs): Promise;\n wait(args: ThreadEventWaitArgs): Promise;\n}\ninterface ThreadQueuedMessagesArea {\n create(args: ThreadQueuedMessageCreateArgs): Promise;\n delete(args: ThreadQueuedMessageTargetArgs): Promise;\n list(args: ThreadQueuedMessageArgs): Promise;\n reorder(args: ThreadQueuedMessageReorderArgs): Promise;\n send(args: ThreadQueuedMessageSendArgs): Promise;\n setGroupBoundary(args: ThreadQueuedMessageGroupBoundaryArgs): Promise;\n update(args: ThreadQueuedMessageUpdateArgs): Promise;\n}\ninterface ThreadTabsArea {\n get(args: ThreadStatusArgs): Promise;\n update(args: ThreadTabsUpdateArgs): Promise;\n}\ninterface ThreadsArea {\n archive(args: ThreadActionArgs): Promise;\n archiveAll(args: ThreadActionArgs): Promise;\n childSummary(args: ThreadStatusArgs): Promise;\n conversationOutline(args: ThreadStatusArgs): Promise;\n defaultExecutionOptions(args: ThreadStatusArgs): Promise;\n delete(args: ThreadDeleteArgs): Promise;\n events: ThreadEventsArea;\n get(args: ThreadGetArgs): Promise;\n interactions: ThreadInteractionsArea;\n list(args?: ThreadListArgs): Promise;\n markRead(args: ThreadActionArgs): Promise;\n markUnread(args: ThreadActionArgs): Promise;\n open(args: ThreadOpenArgs): Promise;\n paneAction(args: ThreadPaneActionArgs): Promise;\n output(args: ThreadOutputArgs): Promise;\n pin(args: ThreadActionArgs): Promise;\n promptHistory(args: ThreadPromptHistoryArgs): Promise;\n queuedMessages: ThreadQueuedMessagesArea;\n reorderPinned(args: ThreadPinOrderArgs): Promise;\n search(args: ThreadSearchArgs): Promise;\n send(args: ThreadSendArgs): Promise;\n spawn(args: ThreadSpawnArgs): Promise;\n stop(args: ThreadActionArgs): Promise;\n tabs: ThreadTabsArea;\n timeline(args: ThreadTimelineArgs): Promise;\n timelineTurnSummaryDetails(args: ThreadTimelineTurnSummaryDetailsArgs): Promise;\n storageFiles(args: ThreadStorageFilesArgs): Promise;\n storagePaths(args: ThreadStoragePathsArgs): Promise;\n unarchive(args: ThreadActionArgs): Promise;\n unpin(args: ThreadActionArgs): Promise;\n update(args: ThreadUpdateArgs): Promise;\n wait(args: ThreadWaitArgs): Promise;\n}\n\ntype ThreadSectionCreateResult = ThreadSectionResponse;\ntype ThreadSectionUpdateResult = ThreadSectionMutationResponse;\ntype ThreadSectionDeleteResult = ThreadSectionMutationResponse;\ntype ThreadSectionListResult = ThreadSectionResponse[];\ninterface ThreadSectionListArgs {\n signal?: AbortSignal;\n}\ninterface ThreadSectionsArea {\n create(args: CreateThreadSectionRequest): Promise;\n delete(args: DeleteThreadSectionRequest): Promise;\n list(args?: ThreadSectionListArgs): Promise;\n update(args: UpdateThreadSectionRequest): Promise;\n}\n\ninterface BbSdk extends BbRealtime {\n environments: EnvironmentsArea;\n files: FilesArea;\n guide: GuideArea;\n hosts: HostsArea;\n members: MembersArea;\n presence: PresenceArea;\n projects: ProjectsArea;\n plugins: PluginsArea;\n providers: ProvidersArea;\n status: StatusArea;\n system: SystemArea;\n terminals: TerminalsArea;\n theme: ThemeArea;\n threadSections: ThreadSectionsArea;\n threads: ThreadsArea;\n}\n\n/**\n * The backend plugin API contract — the `bb` object handed to a plugin's\n * `server.ts` factory (`export default function plugin(bb: BbPluginApi)`).\n *\n * Types only: the implementation lives in the BB server\n * (apps/server/src/services/plugins/plugin-api.ts), which imports these\n * shapes so the contract and the implementation cannot drift. Plugin authors\n * import them type-only (`import type { BbPluginApi } from\n * \"@bb/plugin-sdk\"`); the import is erased when BB loads the file.\n *\n * Runtime classes stay host-side. NeedsConfigurationError in particular is\n * matched by NAME, so plugin code needs no runtime import:\n * `throw Object.assign(new Error(msg), { name: \"NeedsConfigurationError\" })`.\n */\ninterface PluginLogger {\n debug(message: string): void;\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n/**\n * Declarative settings descriptors (`bb.settings.define`). Deliberately plain\n * data — not zod — so the host can render settings forms and the CLI can\n * parse values without executing plugin code.\n */\ntype PluginSettingDescriptor = {\n type: \"string\";\n label: string;\n description?: string;\n /** Stored in a 0600 file under /plugins//secrets/, never in the db or sent to the frontend. */\n secret?: true;\n default?: string;\n} | {\n type: \"boolean\";\n label: string;\n description?: string;\n default?: boolean;\n} | {\n type: \"select\";\n label: string;\n description?: string;\n options: string[];\n default?: string;\n} | {\n type: \"project\";\n label: string;\n description?: string;\n default?: string;\n};\ntype PluginSettingDescriptors = Record;\ntype PluginSettingValue = string | boolean;\n/** `default` present → non-optional value; absent → `T | undefined`. */\ntype PluginSettingsValues> = {\n [K in keyof Ds]: Ds[K] extends {\n default: string | boolean;\n } ? PluginSettingValueOf : PluginSettingValueOf | undefined;\n};\ntype PluginSettingValueOf = D extends {\n type: \"boolean\";\n} ? boolean : string;\ninterface PluginSettingsHandle> {\n /** Load-safe: callable inside the factory. */\n get(): Promise>;\n /** Fires after values change through the settings route/CLI. */\n onChange(listener: (next: PluginSettingsValues, prev: PluginSettingsValues) => void): void;\n}\ninterface PluginSettings {\n define>(descriptors: Ds): PluginSettingsHandle;\n}\ninterface PluginKvStorage {\n get(key: string): Promise;\n set(key: string, value: unknown): Promise;\n delete(key: string): Promise;\n list(prefix?: string): Promise;\n}\ninterface PluginStorage {\n /** Namespaced JSON key-value rows in bb.db; values ≤256KB each. */\n kv: PluginKvStorage;\n /**\n * Open (or reuse the path of) the plugin's own SQLite database at\n * /plugins//data.db — the server's better-sqlite3, WAL mode,\n * busy_timeout 5000. Handles are host-tracked and closed on\n * dispose/reload; a closed handle throws on use.\n */\n database(): Database.Database;\n /**\n * Ordered-statement migration helper: statement index = migration id in a\n * `_bb_migrations` table; unapplied statements run in one transaction.\n * Append-only — never reorder or edit shipped statements.\n */\n migrate(db: Database.Database, statements: string[]): void;\n}\n/**\n * Thread lifecycle events a plugin can observe (design §4.5). Observe-only:\n * handlers run fire-and-forget after the transition is applied and can never\n * block or veto it. `thread` is the same public DTO GET /threads/:id serves.\n */\ninterface PluginThreadEventPayloads {\n /** Fired after a thread row is created. */\n \"thread.created\": {\n thread: ThreadResponse;\n };\n /** Fired when a thread transitions into `active`. */\n \"thread.active\": {\n thread: ThreadResponse;\n };\n /** Fired when a thread transitions into `idle`. `lastAssistantText` is\n * assembled the same way GET /threads/:id/output is. */\n \"thread.idle\": {\n thread: ThreadResponse;\n lastAssistantText: string | null;\n };\n /** Fired when a thread transitions into `error`. `error` is the latest\n * system/error event message, when one exists. */\n \"thread.failed\": {\n thread: ThreadResponse;\n error: string | null;\n };\n /** Fired after a thread is soft-deleted. */\n \"thread.deleted\": {\n thread: ThreadResponse;\n };\n}\ntype PluginThreadEventName = keyof PluginThreadEventPayloads;\ntype PluginThreadEventHandler = (payload: PluginThreadEventPayloads[E]) => void | Promise;\ntype PluginHttpAuthMode = \"local\" | \"token\" | \"none\";\ntype PluginHttpHandler = (context: Context) => Response | Promise;\ninterface PluginHttp {\n /**\n * Register an HTTP route, mounted at\n * `/api/v1/plugins//http/`. Auth modes (default \"local\"):\n * - \"local\": Origin/Host must be a local BB app origin; non-GET requires\n * content-type application/json (forces a CORS preflight).\n * - \"token\": requires the per-plugin token (`bb plugin token `) via\n * the x-bb-plugin-token header or ?token=.\n * - \"none\": no checks — only for signature-verified webhooks.\n */\n route(method: string, path: string, handler: PluginHttpHandler, opts?: {\n auth?: PluginHttpAuthMode;\n }): void;\n}\ninterface PluginRpc {\n /**\n * Register a Standard Schema-driven rpc contract and its inferred handlers,\n * served at POST\n * `/api/v1/plugins//rpc/` with \"local\" auth semantics. The\n * host validates input before invocation and output before strict JSON\n * serialization. The response is `{ ok: true, result }` or\n * `{ ok: false, error: { code, message, issues? } }`.\n */\n register(contract: Contract, handlers: PluginRpcHandlers): void;\n}\ninterface PluginRealtime {\n /**\n * Broadcast an ephemeral `plugin-signal` WS message\n * `{ pluginId, channel, payload }` to every connected client (V1 has no\n * per-channel subscriptions). `payload` must be JSON-serializable;\n * `undefined` is normalized to `null`. Nothing is persisted.\n */\n publish(channel: string, payload: unknown): void;\n}\ninterface PluginBackground {\n /**\n * Register a long-lived background service. `start` runs after the\n * factory completes and should resolve when `signal` aborts\n * (dispose/reload/disable/shutdown). A crash restarts it with capped\n * exponential backoff; throwing NeedsConfigurationError marks the plugin\n * `needs-configuration` and stops restarting until the next load.\n */\n service(name: string, service: {\n start(signal: AbortSignal): void | Promise;\n }): void;\n /**\n * Register a cron schedule (5-field expression, server-local time). The\n * durable row keyed (pluginId, name) is upserted at load; the periodic\n * sweep claims due rows with a CAS on next_run_at, but only while this\n * plugin is loaded. Failures land in last_status/last_error, visible in\n * `bb plugin list`.\n */\n schedule(name: string, cron: string, fn: () => void | Promise): void;\n}\ninterface PluginCliCommandInfo {\n name: string;\n summary: string;\n usage: string;\n}\n/** Context forwarded from the invoking CLI when known; all fields optional. */\ninterface PluginCliContext {\n cwd?: string;\n threadId?: string;\n projectId?: string;\n /** Aborted when the invoking CLI HTTP request disconnects. */\n signal?: AbortSignal;\n}\ntype PluginInteractionCancelReason = \"user\" | \"request-aborted\" | \"thread-stopped\" | \"thread-deleted\" | \"plugin-disposed\" | \"server-restarted\" | \"timeout\";\ntype PluginInteractionResult = {\n outcome: \"submitted\";\n value: JsonValue$1;\n} | {\n outcome: \"cancelled\";\n reason: PluginInteractionCancelReason;\n};\ninterface PluginInteractionRequest {\n threadId: string;\n rendererId: string;\n title: string;\n payload: JsonValue$1;\n /** Defaults to ten minutes; capped at one hour. */\n timeoutMs?: number;\n}\ninterface PluginCliResult {\n exitCode: number;\n stdout?: string;\n stderr?: string;\n}\n/**\n * Maximum combined UTF-8 bytes accepted from plugin CLI stdout and stderr.\n * This is the shared source of truth for production and the testing harness.\n */\ndeclare const PLUGIN_CLI_OUTPUT_MAX_BYTES: number;\ninterface PluginCliOutputLimitError {\n code: \"plugin_cli_output_too_large\";\n message: string;\n maxBytes: number;\n stdoutBytes: number;\n stderrBytes: number;\n totalBytes: number;\n}\n/** Normalized host result returned by the plugin CLI HTTP/testing boundary. */\ninterface PluginCliExecutionResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n error?: PluginCliOutputLimitError;\n}\ninterface PluginCliRegistration {\n /** Top-level command name (`bb …`): lowercase [a-z0-9-]+, and not\n * a core bb command (see RESERVED_BB_CLI_COMMANDS in the server). */\n name: string;\n summary: string;\n /** Subcommand metadata rendered in help and the plugin-commands skill\n * without executing plugin code. Parsing argv is plugin-owned. */\n commands?: PluginCliCommandInfo[];\n run(argv: string[], ctx: PluginCliContext): PluginCliResult | Promise;\n}\ninterface PluginCli {\n /**\n * Register this plugin's `bb` subcommand. One registration per factory\n * execution; a repeated call is rejected. Core bb commands always win\n * name collisions; reserved names are rejected at registration.\n */\n register(registration: PluginCliRegistration): void;\n}\n/** Per-turn context handed to bb.agents context providers (design §4.4). */\n/** MCP-style content parts a native tool may return (design §4.4). */\ntype PluginAgentToolContentPart = {\n type: \"text\";\n text: string;\n} | {\n type: \"image\";\n data: string;\n mimeType: string;\n};\ntype PluginAgentToolResult = string | {\n content: PluginAgentToolContentPart[];\n isError?: boolean;\n};\n/** Per-call context handed to a native tool's execute (design §4.4). */\ninterface PluginAgentToolContext {\n threadId: string;\n projectId: string;\n /** The tool-call request's abort signal (aborts if the daemon round-trip\n * is torn down mid-call). */\n signal: AbortSignal;\n}\ninterface PluginAgentToolRegistrationBase {\n /** Tool name shown to the model: [a-zA-Z0-9_-]+, unique across plugins,\n * and not a built-in dynamic tool (see RESERVED_AGENT_TOOL_NAMES in the\n * server). */\n name: string;\n description: string;\n /**\n * Optional usage snippet appended to the thread instructions whenever\n * this tool is in the session's tool set (mirrors the built-in\n * update_environment_directory guidance). Limited to 4096 characters.\n */\n instructions?: string;\n}\n/** Stable, plain-data context resolved by the server for one agent session. */\ninterface PluginAgentConfigurationContext {\n thread: {\n id: string;\n title: string | null;\n parentThreadId: string | null;\n sourceThreadId: string | null;\n };\n project: {\n id: string;\n kind: \"standard\" | \"personal\";\n name: string;\n gitRemoteUrl: string | null;\n };\n environment: {\n id: string;\n name: string | null;\n path: string | null;\n workspaceProvisionType: \"unmanaged\" | \"managed-worktree\" | \"personal\";\n branchName: string | null;\n };\n host: {\n id: string;\n name: string;\n };\n provider: {\n id: string;\n model: string;\n };\n sideChat: boolean;\n origin: {\n kind: \"fork\" | \"side-chat\" | null;\n pluginId: string | null;\n };\n}\n/** Object form of a {@link PluginAgentConfiguration} tools entry: selects a\n * registered tool and overrides the parameter schema advertised to the\n * provider for this resolution only. */\ninterface PluginAgentToolSelection {\n /** Name of a tool registered by this plugin via `registerTool`. */\n name: string;\n /** JSON-schema object (root `type: \"object\"`, JSON-serializable, at most\n * 128 KiB serialized) sent to the provider in place of the registered\n * parameter schema. Execution-side validation still runs the registered\n * parameters, so the override must only narrow what the registered schema\n * already accepts. */\n parameters: Record;\n}\n/** Per-resolution selection returned by {@link PluginAgents.configure}. */\ninterface PluginAgentConfiguration {\n /** Tool names registered by this plugin, or {@link PluginAgentToolSelection}\n * entries to also override a tool's advertised parameter schema for this\n * resolution. Duplicate or unknown names, or an invalid override, reject\n * this plugin's complete selection for the resolution. */\n tools: Array;\n /** Skill frontmatter names from this plugin's manifest skill roots.\n * Duplicate or unknown names reject this plugin's complete selection. */\n skills: string[];\n /** Optional dynamic instructions. Output is truncated to 4096 characters. */\n instructions?: string;\n}\ninterface PluginAgents {\n /**\n * Select this plugin's statically registered tools and manifest skills for\n * each thread/session resolution, with optional dynamic instructions. The\n * callback is synchronous and runs at `thread.start` / `turn.submit`; it\n * never rebuilds registrations. Exactly one callback may be registered per\n * factory execution. A throw, malformed result, duplicate id, unknown id,\n * or more than 256 tool/skill ids fails closed for this plugin only.\n *\n * Tools take effect when the provider session is next started or resumed;\n * an already-running session is not hot-mutated. Instructions are resolved\n * for the next turn. Skill changes follow BB's environment runtime policy:\n * a busy runtime keeps its current catalog until a safe relaunch. Side-chat\n * threads receive `sideChat: true`, and their returned tool, skill, and\n * dynamic-instruction selections apply at the same boundaries. Independent\n * side-chat safety policy (such as permission escalation) is unchanged.\n */\n configure(provider: (context: PluginAgentConfigurationContext) => PluginAgentConfiguration): void;\n /**\n * Register a native dynamic tool (design §4.4). `parameters` is either a\n * zod schema (validated per call; execute receives the parsed value) or a\n * plain JSON-schema object (no validation; execute receives the raw\n * arguments as `unknown`). Tool-set changes apply on the NEXT session\n * start — a tool registered mid-session is not hot-added to running\n * provider sessions. A second registration of the same name within this\n * plugin is rejected; a name already registered by another plugin is\n * rejected and surfaced as this plugin's status detail.\n */\n registerTool(tool: PluginAgentToolRegistrationBase & {\n parameters: Schema;\n execute(params: z.output, ctx: PluginAgentToolContext): PluginAgentToolResult | Promise;\n }): void;\n registerTool(tool: PluginAgentToolRegistrationBase & {\n /** Raw JSON-schema escape hatch; params arrive unvalidated. */\n parameters: Record;\n execute(params: unknown, ctx: PluginAgentToolContext): PluginAgentToolResult | Promise;\n }): void;\n /**\n * Contribute a dynamic section appended to thread instructions. The\n * provider runs when a thread's runtime command config is resolved\n * (thread.start / turn.submit); return null to contribute nothing for\n * that resolution. Must be synchronous and fast — it sits on the\n * thread-start path. Output longer than 4096 characters is truncated; a\n * throwing provider is logged against the plugin and contributes nothing.\n * A repeated registration within one factory execution is rejected.\n * This legacy contribution is not applied to side-chat threads; use\n * configure() when sideChat-aware dynamic instructions are required.\n */\n contributeInstructions(provider: (ctx: {\n threadId: string;\n projectId: string;\n }) => string | null): void;\n}\ninterface PluginThreadActionContext {\n threadId: string;\n projectId: string;\n}\ninterface PluginThreadActionToast {\n kind: \"success\" | \"error\" | \"info\";\n message: string;\n}\ntype PluginThreadActionResult = void | {\n toast?: PluginThreadActionToast;\n};\ninterface PluginThreadActionRegistration {\n /** Unique within this plugin: [a-zA-Z0-9_-]+ (becomes a URL segment). */\n id: string;\n /** Button label rendered in the thread header. */\n title: string;\n /** Optional icon name; the host falls back to a generic icon. */\n icon?: string;\n /** Optional confirmation prompt the host shows before running. */\n confirm?: string;\n /**\n * Runs server-side when the user clicks the action. The host shows a\n * pending state while in flight, the returned toast on completion, and an\n * automatic error toast when this throws.\n */\n run(ctx: PluginThreadActionContext): PluginThreadActionResult | Promise;\n}\ntype PluginMentionTrigger = \"@\" | \"#\" | \"$\" | \"!\" | \"~\";\n/** Search context handed to a mention provider (design §4.9). `projectId`/\n * `threadId` are null when the composer has not committed one yet. */\ninterface PluginMentionSearchContext {\n trigger: PluginMentionTrigger;\n query: string;\n projectId: string | null;\n threadId: string | null;\n}\n/** One row a mention provider returns from `search`. `id` is the provider's\n * own item id — the host namespaces it before it reaches the wire. */\ninterface PluginMentionItem {\n id: string;\n title: string;\n subtitle?: string;\n icon?: string;\n}\ninterface PluginMentionProviderRegistration {\n /** Unique within this plugin: [a-zA-Z0-9_-]+ (no \":\" — the host composes\n * wire item ids as \":\"). */\n id: string;\n /** Section label shown above this provider's rows in the mention menu. */\n label: string;\n /**\n * Composer trigger characters this provider should answer. Omit to use the\n * default `@` mention trigger. Valid triggers are `@`, `#`, `$`, `!`, and `~`.\n */\n triggers?: readonly PluginMentionTrigger[];\n /**\n * Runs server-side as the user types after one of this provider's triggers\n * in the composer. Each call is time-boxed (2s) and failure-isolated: a slow\n * or throwing provider contributes an empty list — it can never break the\n * mention menu.\n */\n search(ctx: PluginMentionSearchContext): PluginMentionItem[] | Promise;\n /**\n * Resolves one picked item into agent context, called once per unique\n * item at message send time. The returned `context` is attached to the\n * message as an agent-visible (user-hidden) prompt input. Throwing blocks\n * the send with a visible error.\n */\n resolve(itemId: string): {\n context: string;\n } | Promise<{\n context: string;\n }>;\n}\ninterface PluginUi {\n /** Block until the app submits or cancels a plugin-owned composer form. */\n requestInput(request: PluginInteractionRequest, options?: {\n signal?: AbortSignal;\n }): Promise;\n /**\n * Register a thread action rendered in the shipped app's thread header\n * (design §4.9). Multiple actions per plugin; ids must be unique within\n * the plugin. Invoked via POST /plugins/:id/actions/:actionId.\n */\n registerThreadAction(action: PluginThreadActionRegistration): void;\n /**\n * Register a mention provider for the shipped app's composer (design §4.9).\n * Providers default to the `@` trigger and may opt into `#`, `$`, `!`, or\n * `~` with `triggers`. Items group under `label` in the mention menu; a\n * picked item becomes a `{ kind: \"plugin\" }` mention resource whose context\n * is resolved once at send time. Multiple providers per plugin; ids must be\n * unique within the plugin.\n */\n registerMentionProvider(provider: PluginMentionProviderRegistration): void;\n}\ninterface PluginEvents {\n /**\n * Add a thread lifecycle listener. Multiple listeners for the same event are\n * additive and run independently in registration order.\n */\n on(event: E, handler: PluginThreadEventHandler): void;\n}\ninterface PluginServerApi {\n /**\n * This BB server's own loopback base URL (e.g. \"http://127.0.0.1:38886\"),\n * which serves the SPA + /api + /ws. For plugins that proxy or relay\n * traffic back to the server itself (e.g. a tunnel). Bind-gated like\n * `bb.sdk`: reading it before the server is listening throws, so prefer\n * reading it from handlers, services, and timers.\n */\n readonly loopbackBaseUrl: string;\n}\ninterface PluginSharedPortTunnelIdentity {\n /** Gate routing label assigned to this machine. */\n label: string;\n /** Gate apex without a scheme, e.g. \"getbb.app\". */\n baseDomain: string;\n}\ninterface PluginHosts {\n /**\n * Ensure this enrolled host has a gate label and return its read-only public\n * identity. The daemon chooses the trusted gate and desired label; plugins\n * cannot influence either credential-bearing destination.\n */\n ensureSharedPortTunnel(hostId: string): Promise;\n /**\n * Replace this plugin's desired shared-loopback ports for one host. The\n * server aggregates declarations, owns generations, and delivers the\n * resulting set to that host's daemon. Tunnel identity is deliberately not\n * accepted here: it is owned by the daemon's trusted enrollment.\n */\n declareSharedPorts(hostId: string, ports: readonly number[]): void;\n}\ninterface PluginStatusApi {\n /**\n * Mark this plugin `needs-configuration` (with a message shown in\n * `bb plugin list` and the UI) instead of failing — e.g. a factory or\n * service that finds no API key configured. Cleared on the next load;\n * saving settings does not auto-reload in V1, so ask the user to\n * `bb plugin reload ` after configuring.\n */\n needsConfiguration(message: string): void;\n}\n/**\n * The API object handed to a plugin's factory (design §4). Implemented by\n * the BB server; this contract is what plugin `server.ts` files compile\n * against.\n */\ninterface BbPluginApi {\n /** The plugin's own id (namespaces storage, routes, commands). */\n readonly pluginId: string;\n /** Leveled, plugin-scoped logger. */\n readonly log: PluginLogger;\n /** Declarative settings (design §4.2). */\n readonly settings: PluginSettings;\n /** Namespaced KV + per-plugin database (design §4.3). */\n readonly storage: PluginStorage;\n /** HTTP routes under /api/v1/plugins//http/* (design §4.6). */\n readonly http: PluginHttp;\n /** RPC methods under /api/v1/plugins//rpc/ (design §4.6). */\n readonly rpc: PluginRpc;\n /** Ephemeral push to connected frontends (design §4.7). */\n readonly realtime: PluginRealtime;\n /** Long-lived services + cron schedules (design §4.8). */\n readonly background: PluginBackground;\n /** Agent-facing `bb` CLI subcommand (design §4.4). */\n readonly cli: PluginCli;\n /** Per-turn agent context contributions (design §4.4). */\n readonly agents: PluginAgents;\n /** Host-rendered UI contributions (design §4.9). */\n readonly ui: PluginUi;\n /** Additive plugin lifecycle listeners (design §4.5). */\n readonly events: PluginEvents;\n /** Plugin-reported status (needs-configuration). */\n readonly status: PluginStatusApi;\n /** Read-only facts about the running server (loopback base URL). */\n readonly server: PluginServerApi;\n /** Server-to-daemon host control-plane declarations. */\n readonly hosts: PluginHosts;\n /**\n * The full BB SDK, bound to this server over loopback (design §4.1).\n * Bind-gated: reading this before the host binds the SDK throws. The real\n * server binds it before loading plugins, so it is available from the\n * moment factories run there — but isolated harnesses may not, so prefer\n * using it from handlers, services, and timers for portability.\n * `threads.spawn` defaults `origin` to \"plugin\" and `originPluginId` to\n * this plugin's id so spawned threads are attributed automatically.\n */\n readonly sdk: BbSdk;\n /**\n * Register cleanup to run on reload/disable/shutdown. Hooks run LIFO.\n * The sanctioned place to clear timers and close connections.\n */\n onDispose(hook: () => void | Promise): void;\n}\n\nexport { PLUGIN_CLI_OUTPUT_MAX_BYTES, defineRpcContract };\nexport type { BbContext, BbNavigate, BbPluginApi, JsonValue$1 as JsonValue, PluginAgentConfiguration, PluginAgentConfigurationContext, PluginAgentToolContentPart, PluginAgentToolContext, PluginAgentToolRegistrationBase, PluginAgentToolResult, PluginAgentToolSelection, PluginAgents, PluginAppBuilder, PluginAppDefinition, PluginAppSetup, PluginAppSlots, PluginBackground, PluginCli, PluginCliCommandInfo, PluginCliContext, PluginCliExecutionResult, PluginCliOutputLimitError, PluginCliRegistration, PluginCliResult, PluginComposerAccessoryProps, PluginComposerAccessoryRegistration, PluginComposerApi, PluginComposerMention, PluginComposerScope, PluginEvents, PluginFileOpenerProps, PluginFileOpenerRegistration, PluginFileOpenerSource, PluginHomepageSectionProps, PluginHomepageSectionRegistration, PluginHosts, PluginHttp, PluginHttpAuthMode, PluginHttpHandler, PluginInteractionCancelReason, PluginInteractionRequest, PluginInteractionResult, PluginKvStorage, PluginLogger, PluginMentionItem, PluginMentionProviderRegistration, PluginMentionSearchContext, PluginMentionTrigger, PluginMessageDirectiveMessage, PluginMessageDirectiveOpenThreadPanel, PluginMessageDirectiveOpenWorkspaceFile, PluginMessageDirectiveProps, PluginMessageDirectiveRegistration, PluginMessageDirectiveThreadPanelOptions, 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 };\n"; export const PLUGIN_SDK_APP_DTS = "// Portable type declarations for `@bb/plugin-sdk`. Unpublished BB\n// workspace contracts are flattened; public subpaths may reuse the\n// package root without requiring any other @bb/* package.\n//\n// Confused by the API, or need a symbol that isn't here? Clone the BB repo\n// and read the real source: https://github.com/ymichael/bb\n\nimport { ComponentType } from 'react';\n\n/** A JSON-safe path segment reported by a Standard Schema validation issue. */\ntype PluginRpcIssuePathSegment = string | number;\n/** Validator-neutral validation detail carried by an RPC error envelope. */\ninterface PluginRpcValidationIssue {\n message: string;\n path?: PluginRpcIssuePathSegment[];\n}\n/** Stable wire error categories for plugin RPC. */\ntype PluginRpcErrorCode = \"invalid_json\" | \"invalid_input\" | \"handler_error\" | \"invalid_output\" | \"non_json_result\" | \"unknown_method\";\n/** Structured RPC failure returned as `{ ok: false, error }`. */\ninterface PluginRpcError {\n code: PluginRpcErrorCode;\n message: string;\n issues?: PluginRpcValidationIssue[];\n}\n/**\n * The validator-neutral subset of Standard Schema v1 used by plugin RPC.\n * Zod 4 schemas implement this interface directly; other validators can do\n * the same without becoming part of BB's public protocol.\n */\ninterface StandardSchemaV1 {\n readonly \"~standard\": {\n readonly version: 1;\n readonly vendor: string;\n readonly validate: (value: unknown) => StandardSchemaV1Result | Promise>;\n readonly types?: {\n readonly input: Input;\n readonly output: Output;\n };\n };\n}\ntype StandardSchemaV1Result = {\n readonly value: Output;\n readonly issues?: undefined;\n} | {\n readonly issues: readonly StandardSchemaV1Issue[];\n};\ninterface StandardSchemaV1Issue {\n readonly message: string;\n readonly path?: PropertyKey | readonly (PropertyKey | {\n readonly key: PropertyKey;\n })[];\n}\ntype StandardSchemaV1InferInput = NonNullable[\"input\"];\ntype StandardSchemaV1InferOutput = NonNullable[\"output\"];\ninterface PluginRpcMethodContract {\n readonly input: InputSchema;\n readonly output: OutputSchema;\n}\ntype PluginRpcContract = Readonly>;\ntype PluginRpcHandlers = {\n [Method in keyof Contract]: (input: StandardSchemaV1InferOutput) => StandardSchemaV1InferInput | Promise>;\n};\ntype PluginRpcCallInput = StandardSchemaV1InferInput;\ntype PluginRpcCallArgs = null extends PluginRpcCallInput ? [input?: PluginRpcCallInput] : [input: PluginRpcCallInput];\ntype PluginRpcResult = StandardSchemaV1InferOutput;\n\n/**\n * A value that survives a JSON round trip without coercion or data loss.\n *\n * Host boundaries still validate values at runtime because TypeScript cannot\n * exclude non-finite numbers and plugin bundles can bypass static types.\n */\ntype JsonValue = string | number | boolean | null | JsonValue[] | {\n [key: string]: JsonValue;\n};\n\n/**\n * The `@bb/plugin-sdk/app` contract (plugin design §5.2) — pure types with no\n * side effects. The BB app imports these to keep its real implementation in\n * sync (`satisfies PluginSdkApp`). Plugin authors import the same shapes through\n * `@bb/plugin-sdk/app`.\n *\n * Per-slot props are versioned contracts: additive-only within an SDK major.\n */\n/** Props passed to a `homepageSection` component. */\ninterface PluginHomepageSectionProps {\n /** Project in view on the compose surface; null when none is selected. */\n projectId: string | null;\n}\n/**\n * Props passed to a `settingsSection` component.\n *\n * Deliberately empty in V1; versioned additive like the other slot props.\n */\ninterface PluginSettingsSectionProps {\n}\n/** Props passed to a `navPanel` component (it owns its whole route). */\ninterface PluginNavPanelProps {\n /**\n * The route remainder after the panel root, \"\" at the root. The panel's\n * route is `/plugins///*`, so a deep link like\n * `/plugins/notes/notes/work/ideas.md` renders the panel with\n * `subPath: \"work/ideas.md\"`. Navigate within the panel via\n * `useBbNavigate().toPluginPanel(path, { subPath })` — browser\n * back/forward then walks panel-internal history.\n */\n subPath: string;\n}\n/** Props passed to a panel tab opened by a `threadPanelAction`. */\ninterface PluginThreadPanelProps {\n threadId: string;\n /**\n * The JSON value the action's `openPanel` call passed (round-tripped\n * through persistence, so the tab restores across reloads); null when the\n * action opened the panel without params.\n */\n params: JsonValue | null;\n}\n/** Props passed to a `composerAccessory` component. */\ninterface PluginComposerAccessoryProps {\n projectId: string | null;\n threadId: string | null;\n}\ninterface PluginPendingInteractionView {\n id: string;\n threadId: string;\n title: string;\n payload: JsonValue;\n createdAt: number;\n expiresAt: number | null;\n}\ninterface PluginPendingInteractionProps {\n interaction: PluginPendingInteractionView;\n submit(value: JsonValue): Promise;\n cancel(): Promise;\n}\n/**\n * Props for a `sidebarFooterAction` — host-rendered (no plugin component).\n * Deliberately empty; the registration's `run` carries the behavior.\n */\ninterface PluginSidebarFooterActionProps {\n}\n/**\n * Where a file being opened by a `fileOpener` lives. `path` semantics follow\n * the source: workspace paths are relative to the environment's worktree,\n * thread-storage paths are relative to the thread's storage root, host paths\n * are absolute on the thread's host.\n */\ninterface PluginFileOpenerSource {\n kind: \"workspace\" | \"host\" | \"thread-storage\";\n threadId: string | null;\n environmentId: string | null;\n projectId: string | null;\n}\n/** Props passed to a `fileOpener` component (rendered as a panel file tab). */\ninterface PluginFileOpenerProps {\n path: string;\n source: PluginFileOpenerSource;\n}\n/**\n * Message context passed to a `messageDirective` component — the assistant\n * (or nested agent) message that contained the directive.\n */\ninterface PluginMessageDirectiveMessage {\n id: string;\n threadId: string;\n turnId: string | null;\n projectId: string | null;\n}\n/**\n * Open a worktree-relative file in the host's workspace file viewer. Returns\n * true when the host accepted the path; false when the path is invalid or the\n * viewer declined it.\n */\ntype PluginMessageDirectiveOpenWorkspaceFile = (path: string) => boolean;\ninterface PluginMessageDirectiveThreadPanelOptions {\n /** A `threadPanelAction` id registered by this same plugin. */\n actionId: string;\n title?: string;\n params?: JsonValue;\n}\n/** Open this plugin's registered action in the current thread side panel. */\ntype PluginMessageDirectiveOpenThreadPanel = (options: PluginMessageDirectiveThreadPanelOptions) => boolean;\n/**\n * Props passed to a `messageDirective` component. Attributes are untrusted\n * strings parsed from the directive; the plugin validates its own fields.\n */\ninterface PluginMessageDirectiveProps {\n /** Parsed, untrusted directive attributes (e.g. `{ file: \"demo.html\" }`). */\n attributes: Readonly>;\n /** Original directive source text (useful for diagnostics / crash fallback). */\n source: string;\n message: PluginMessageDirectiveMessage;\n /**\n * Opens a worktree-relative file in the host's workspace file viewer. Null\n * when the message surface has no workspace viewer available.\n */\n openWorkspaceFile: PluginMessageDirectiveOpenWorkspaceFile | null;\n /**\n * Opens one of this plugin's own `threadPanelAction` components in the\n * current thread side panel. Omitted by older hosts; null on message\n * surfaces without a thread panel.\n */\n openThreadPanel?: PluginMessageDirectiveOpenThreadPanel | null;\n}\ninterface PluginHomepageSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n component: ComponentType;\n}\ninterface PluginSettingsSectionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Optional host-rendered section heading. */\n title?: string;\n /**\n * Optional one-line host-rendered subheading under `title`, in the built-in\n * SettingsSection idiom (ignored when `title` is absent).\n */\n description?: string;\n component: ComponentType;\n}\ninterface PluginNavPanelRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /** URL segment under `/plugins//`; letters, digits, `-`, `_`. */\n path: string;\n component: ComponentType;\n /**\n * Optional component rendered on the right side of the shared title bar\n * (e.g. a sync button or a count). Contained separately from the body: a\n * throwing headerContent is hidden without breaking the title bar.\n */\n headerContent?: ComponentType;\n}\n/** Context handed to a `threadPanelAction`'s `run`. */\ninterface PluginThreadPanelActionContext {\n /** The thread whose panel launcher invoked the action. */\n threadId: string;\n /**\n * Open a tab in the thread's side panel rendering this action's\n * `component`. `title` labels the tab (default: the action's `title`);\n * `params` must be JSON-serializable — it is persisted with the tab and\n * reaches the component as its `params` prop. Opening with params\n * identical to an already-open tab of this action focuses that tab\n * (updating its title) instead of duplicating it. May be called more than\n * once (different params ⇒ multiple tabs) or not at all.\n */\n openPanel(options?: {\n title?: string;\n params?: JsonValue;\n }): void;\n}\ninterface PluginThreadPanelActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label of the action row in the panel's new-tab launcher. */\n title: string;\n /**\n * Icon hint (BB icon name) used when the plugin ships no logo; the\n * launcher row and opened tabs prefer the plugin's logo.\n */\n icon?: string;\n /** Rendered inside every panel tab this action opens. */\n component: ComponentType;\n /**\n * Runs when the user activates the action: call your RPC methods, show a\n * toast, and/or open panel tabs via `context.openPanel`. Omitted =\n * immediately open a panel tab with defaults. Errors (sync or async) are\n * contained and logged; they never break the launcher.\n */\n run?(context: PluginThreadPanelActionContext): void | Promise;\n}\ninterface PluginComposerAccessoryRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n component: ComponentType;\n}\ninterface PluginPendingInteractionRegistration {\n /** Matches `rendererId` passed to `bb.ui.requestInput`. */\n id: string;\n component: ComponentType;\n}\n/** Context handed to a `sidebarFooterAction`'s `run`. */\ninterface PluginSidebarFooterActionContext {\n /**\n * Navigate to this plugin's Settings detail page\n * (`/settings/plugins/`), where declarative settings and\n * `settingsSection` slots render.\n */\n openSettings(): void;\n}\n/**\n * An icon button in the app sidebar footer (next to Settings / bug report).\n * Host-rendered for consistent chrome — plugins supply icon, label, and\n * `run` behavior only.\n */\ninterface PluginSidebarFooterActionRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Tooltip and accessible label for the icon button. */\n title: string;\n /** Icon hint (BB icon name); unknown names fall back to a generic icon. */\n icon: string;\n /**\n * Runs when the user activates the action (e.g. call `openSettings()`,\n * open a panel via other surfaces, toast). Errors (sync or async) are\n * contained and logged; they never break the sidebar.\n */\n run(context: PluginSidebarFooterActionContext): void | Promise;\n}\n/**\n * Register this plugin as a viewer/editor for file extensions. The user\n * picks (and can set as default) an opener per extension via the file tab's\n * \"Open with\" menu; matching files opened in the panel then render\n * `component` in a plugin tab instead of the built-in preview. Applies to\n * working-tree, host, and thread-storage files — never to git-ref snapshots\n * (diff views always use the built-in preview). The built-in preview stays\n * one menu click away, and a missing/disabled opener falls back to it.\n */\ninterface PluginFileOpenerRegistration {\n /** Unique within the plugin; letters, digits, `-`, `_`. */\n id: string;\n /** Label in the \"Open with\" menu (e.g. \"Notes editor\"). */\n title: string;\n /** Lowercase extensions without the dot (e.g. [\"md\", \"mdx\"]). */\n extensions: readonly string[];\n component: ComponentType;\n}\n/**\n * Register a leaf message directive rendered inside assistant (and nested\n * agent) message Markdown. `id` is the directive name: `inline-vis` matches\n * `::inline-vis{file=\"demo.html\"}`.\n */\ninterface PluginMessageDirectiveRegistration {\n /**\n * The directive name. Lowercase kebab-case beginning with a letter.\n */\n id: string;\n component: ComponentType;\n}\ninterface PluginAppSlots {\n homepageSection(registration: PluginHomepageSectionRegistration): void;\n settingsSection(registration: PluginSettingsSectionRegistration): void;\n navPanel(registration: PluginNavPanelRegistration): void;\n threadPanelAction(registration: PluginThreadPanelActionRegistration): void;\n composerAccessory(registration: PluginComposerAccessoryRegistration): void;\n pendingInteraction(registration: PluginPendingInteractionRegistration): void;\n sidebarFooterAction(registration: PluginSidebarFooterActionRegistration): void;\n fileOpener(registration: PluginFileOpenerRegistration): void;\n messageDirective(registration: PluginMessageDirectiveRegistration): void;\n}\ninterface PluginAppBuilder {\n slots: PluginAppSlots;\n}\ntype PluginAppSetup = (app: PluginAppBuilder) => void;\n/**\n * The opaque product of `definePluginApp` — a plugin's `app.tsx` default\n * export. The host re-runs `setup` against a fresh collector on every\n * (re)interpretation, replacing that plugin's registrations wholesale.\n */\ninterface PluginAppDefinition {\n /** Brand the host checks before interpreting a bundle's default export. */\n readonly __bbPluginApp: true;\n readonly setup: PluginAppSetup;\n}\ninterface PluginRpcClient {\n /**\n * Invoke one of the plugin's `bb.rpc` methods (POST\n * /api/v1/plugins/<id>/rpc/<method>). Resolves with the method's\n * inferred output; rejects with an `Error` carrying the server's message,\n * stable `code`, and validation `issues` when present.\n */\n call>(method: Method, ...args: PluginRpcCallArgs): Promise>;\n}\ninterface PluginSettingsState {\n /**\n * Effective non-secret setting values (secret settings are excluded —\n * read them server-side). Undefined while loading or unavailable.\n */\n values: Record | undefined;\n isLoading: boolean;\n}\n/** State of the app's shared realtime connection to the bb server. */\ntype PluginRealtimeConnectionState = \"connecting\" | \"connected\" | \"reconnecting\";\n/** Where `useComposer()` writes: the active thread's draft or the new-thread draft. */\ntype PluginComposerScope = {\n kind: \"thread\";\n threadId: string;\n} | {\n kind: \"new-thread\";\n projectId: string | null;\n};\n/** An @-mention pill bound to one of the calling plugin's mention providers. */\ninterface PluginComposerMention {\n /** Mention provider id registered by THIS plugin via `bb.ui.registerMentionProvider`. */\n provider: string;\n /** Item id your provider's `resolve` will receive at send time. */\n id: string;\n /** Pill text shown in the composer. */\n label: string;\n}\n/**\n * Programmatic access to the chat composer draft — the same shared draft the\n * built-in \"Add to chat\" affordances (file preview, diff, terminal selections)\n * write to. Inside a thread context writes land in that thread's draft;\n * anywhere else (nav panel, homepage section) they seed the new-thread\n * composer draft, which persists until the user sends or clears it.\n */\ninterface PluginComposerApi {\n scope: PluginComposerScope;\n /** Current plain text for this composer scope. */\n readonly text: string;\n /**\n * Replace the draft's plain text. Attachments are preserved. Inline mentions\n * outside the changed range are preserved and rebased; mentions overlapped\n * by the replacement are removed because their text representation changed.\n */\n setText(next: string): void;\n /**\n * Replace the draft's plain text from the latest committed value. Uses the\n * same structured-state reconciliation as `setText`.\n */\n updateText(updater: (current: string) => string): void;\n /** Clear plain text without clearing independently attached files. */\n clear(): void;\n /**\n * Append text to the draft as a `> ` blockquote block and focus the\n * composer. Blank text is a no-op. This is the \"reference this selection\n * in chat\" primitive.\n */\n addQuote(text: string): void;\n /**\n * Insert an @-mention pill that resolves through this plugin's mention\n * provider at send time — the durable way to reference an entity whose\n * content should be fetched fresh when the message is sent.\n */\n insertMention(mention: PluginComposerMention): void;\n /** Focus the composer caret at the end of the draft. */\n focus(): void;\n}\n/** Current app selection, derived from the route. */\ninterface BbContext {\n projectId: string | null;\n threadId: string | null;\n}\ninterface BbNavigate {\n toThread(threadId: string): void;\n toProject(projectId: string): void;\n /**\n * Navigate to one of this plugin's own nav panels by its `path`.\n * `subPath` targets a location inside the panel (the component's\n * `subPath` prop); `replace` swaps the current history entry instead of\n * pushing — use it for redirects so back does not bounce.\n */\n toPluginPanel(path: string, options?: {\n subPath?: string;\n replace?: boolean;\n }): void;\n /**\n * Navigate to the root compose surface (the new-thread screen). Pass\n * `initialPrompt` to seed the composer draft and `focusPrompt` to focus the\n * composer on arrival — the pairing behind \"Create via chat\" style entry\n * points that drop the user into chat with a prefilled prompt.\n */\n toCompose(options?: {\n initialPrompt?: string;\n focusPrompt?: boolean;\n }): void;\n}\n/**\n * Everything `@bb/plugin-sdk/app` resolves to at runtime. The BB app builds\n * the real implementation and `satisfies` this interface; `bb plugin build`\n * shims the specifier to that object on `globalThis.__bbPluginRuntime`.\n */\ninterface PluginSdkApp {\n definePluginApp(setup: PluginAppSetup): PluginAppDefinition;\n useRpc(): PluginRpcClient;\n useRealtime(channel: string, handler: (payload: unknown) => void): void;\n /**\n * Observe the same shared connection that delivers `useRealtime` signals.\n * Use a subsequent transition to `connected` to reconcile server state that\n * may have changed while ephemeral signals could not be delivered. The first\n * connection can transition from `connecting` and is not a reconnection.\n */\n useRealtimeConnectionState(): PluginRealtimeConnectionState;\n useSettings(): PluginSettingsState;\n useBbContext(): BbContext;\n useBbNavigate(): BbNavigate;\n useComposer(): PluginComposerApi;\n}\n\ndeclare const definePluginApp: (setup: PluginAppSetup) => PluginAppDefinition;\ndeclare const useRpc: , StandardSchemaV1>>>>() => PluginRpcClient;\ndeclare const useRealtime: (channel: string, handler: (payload: unknown) => void) => void;\ndeclare const useRealtimeConnectionState: () => PluginRealtimeConnectionState;\ndeclare const useSettings: () => PluginSettingsState;\ndeclare const useBbContext: () => BbContext;\ndeclare const useBbNavigate: () => BbNavigate;\ndeclare const useComposer: () => PluginComposerApi;\n\nexport { definePluginApp, useBbContext, useBbNavigate, useComposer, useRealtime, useRealtimeConnectionState, useRpc, useSettings };\nexport type { BbContext, BbNavigate, JsonValue, PluginAppBuilder, PluginAppDefinition, PluginAppSetup, PluginAppSlots, PluginComposerAccessoryProps, PluginComposerAccessoryRegistration, PluginComposerApi, PluginComposerMention, PluginComposerScope, PluginFileOpenerProps, PluginFileOpenerRegistration, PluginFileOpenerSource, PluginHomepageSectionProps, PluginHomepageSectionRegistration, PluginMessageDirectiveMessage, PluginMessageDirectiveOpenThreadPanel, PluginMessageDirectiveOpenWorkspaceFile, PluginMessageDirectiveProps, PluginMessageDirectiveRegistration, PluginMessageDirectiveThreadPanelOptions, 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 };\n"; diff --git a/packages/templates/src/generated/templates.generated.ts b/packages/templates/src/generated/templates.generated.ts index bfd54ea870..d8eb2e475c 100644 --- a/packages/templates/src/generated/templates.generated.ts +++ b/packages/templates/src/generated/templates.generated.ts @@ -51,7 +51,7 @@ export const templateDefinitions = [ }, { "id": "bbGuideMachines", - "body": "Machine commands\n\nA machine is a host daemon that can run thread environments. Add remote\nmachines under Settings → Machines.\n\nThe Settings installer first uses the exact `bb-app` tarball served by that bb\nserver at `/install/bb-app.tgz`; only servers that do not implement the route\n(HTTP 404) fall back to npm. Installed launchd/systemd services pass\n`--auto-update`. On a newer server protocol mismatch, the daemon downloads that\nsame artifact, installs it globally with npm, and exits for the service manager\nto restart. Attempts are persisted and limited to once per 15 minutes. A daemon\nnever auto-downgrades to an older server protocol.\n\nTo opt out, remove `--auto-update` from the launchd plist or systemd user unit\nand reload that service. Foreground/manual `bb-app host-daemon` runs leave it off\nunless you pass `--auto-update` explicitly.\n\n bb machine list List machines with ID, connection\n status, and relative last-seen time\n --json Print the raw host list\n bb machine show Show machine details\n bb machine join-code Create a machine pairing code\n bb machine rename Rename a machine\n bb machine remove [--yes] Revoke and remove a machine\n bb machine provider-cli status \n bb machine provider-cli install \n --action \n\nMachine selectors accept either an exact machine ID or an unambiguous machine\nname. `--host` is an alias for `--machine`.\n\n bb thread spawn --project --machine --prompt \"...\"\n bb project create --name \"...\" --root --machine \n bb project source add --machine --path \n\nFor thread spawning, machine targeting works with an unmanaged workspace path,\na new managed worktree, or the personal workspace. Do not combine it with an\nexisting environment ID: the reused environment already selects its machine.\n\nFor project creation and sources, `--root`/`--path` refers to a path on the\nselected connected machine. Omit the selector to keep the existing local CLI\nmachine fallback (normally the primary machine). Pass `--clone` to source add\ninstead of `--path` to clone the project's Git remote there; `--remote-url` and\n`--target-path` optionally override the clone inputs.", + "body": "Machine commands\n\nA machine is a host daemon that can run thread environments. Add remote\nmachines under Settings → Machines.\n\nThe Settings installer first uses the exact `bb-app` tarball served by that bb\nserver at `/install/bb-app.tgz`; only servers that do not implement the route\n(HTTP 404) fall back to npm. Installed launchd/systemd services pass\n`--auto-update`. On a newer server protocol mismatch, the daemon downloads that\nsame artifact, installs it globally with npm, and exits for the service manager\nto restart. Attempts are persisted and limited to once per 15 minutes. A daemon\nnever auto-downgrades to an older server protocol.\n\nTo opt out, remove `--auto-update` from the launchd plist or systemd user unit\nand reload that service. Foreground/manual `bb-app host-daemon` runs leave it off\nunless you pass `--auto-update` explicitly.\n\n bb machine list List machines with ID, connection\n status, and relative last-seen time\n --json Print the raw host list\n bb machine show Show machine details\n bb machine join-code Create a machine pairing code\n bb machine rename Rename a machine\n bb machine remove [--yes] Revoke and remove a machine\n bb machine provider-cli status \n bb machine provider-cli install \n --action \n\nMachine selectors accept either an exact machine ID or an unambiguous machine\nname. `--host` is an alias for `--machine`.\n\n bb thread spawn --project --machine --prompt \"...\"\n bb project create --name \"...\" --root --machine \n bb project source add --machine --path \n\nFor thread spawning, machine targeting works with an unmanaged workspace path,\na new managed worktree, or the personal workspace. Do not combine it with an\nexisting environment ID: the reused environment already selects its machine.\n\nFor project creation and sources, `--root`/`--path` refers to a path on the\nselected connected machine. Omit the selector to keep the existing local CLI\nmachine fallback (normally the primary machine). Pass `--clone` to source add\ninstead of `--path` to clone the project's Git remote there; `--remote-url` and\n`--target-path` optionally override the clone inputs.\n\n## Multiplayer Members\n\nOwners can invite other Connect accounts to their bb. Members admitted through\nthe gate use the full app; their messages and actions are attributed to their\nclaimed identity, and presence (who is viewing which thread, who is typing)\nappears in the thread header and sidebar.\n\n bb members list List members admitted through Connect\n bb members add Add a Connect account by handle\n bb members remove Remove a member by handle\n --json Machine-readable output (all subcommands)\n\nMember management is owner-console-only: it works from the machine itself and\nis rejected for sessions arriving through the Connect tunnel. The Connect\naudit log records verified admissions and membership changes. Identity inside\nbb is claimed, not verified — clients self-assert a handle (the app prompts\nremote visitors for a display name); attribution is honor-system by design\nbecause anyone admitted has full access anyway.", "fileName": "bb-guide-machines.md", "kind": "instruction", "title": "bb Guide — Machines", diff --git a/packages/templates/src/templates/bb-guide-machines.md b/packages/templates/src/templates/bb-guide-machines.md index 5ae85bd8f7..deb4786731 100644 --- a/packages/templates/src/templates/bb-guide-machines.md +++ b/packages/templates/src/templates/bb-guide-machines.md @@ -49,3 +49,22 @@ selected connected machine. Omit the selector to keep the existing local CLI machine fallback (normally the primary machine). Pass `--clone` to source add instead of `--path` to clone the project's Git remote there; `--remote-url` and `--target-path` optionally override the clone inputs. + +## Multiplayer Members + +Owners can invite other Connect accounts to their bb. Members admitted through +the gate use the full app; their messages and actions are attributed to their +claimed identity, and presence (who is viewing which thread, who is typing) +appears in the thread header and sidebar. + + bb members list List members admitted through Connect + bb members add Add a Connect account by handle + bb members remove Remove a member by handle + --json Machine-readable output (all subcommands) + +Member management is owner-console-only: it works from the machine itself and +is rejected for sessions arriving through the Connect tunnel. The Connect +audit log records verified admissions and membership changes. Identity inside +bb is claimed, not verified — clients self-assert a handle (the app prompts +remote visitors for a display name); attribution is honor-system by design +because anyone admitted has full access anyway. diff --git a/packages/tunnel-client/src/headers.ts b/packages/tunnel-client/src/headers.ts index 8e212e4d3a..939c144312 100644 --- a/packages/tunnel-client/src/headers.ts +++ b/packages/tunnel-client/src/headers.ts @@ -5,11 +5,16 @@ const SKIP_REQUEST_HEADERS = new Set([ "content-length", "connection", "accept-encoding", + "x-bb-via-tunnel", ]); +export const TUNNEL_ORIGIN_HEADER = "x-bb-via-tunnel"; + export interface LoopbackHeaderRewrite { publicOrigin: string; loopbackOrigin: string; + /** Stamp the trusted marker when this header set is re-issued by a tunnel. */ + markTunnelOrigin?: boolean; /** * When set, inject a Host header (share streams). When omitted, Host is * dropped — bare-handle behavior, byte-identical to pre-share. @@ -33,5 +38,8 @@ export function headersForLoopbackRequest( if (rewrite.host !== undefined) { forwarded.Host = rewrite.host; } + if (rewrite.markTunnelOrigin) { + forwarded[TUNNEL_ORIGIN_HEADER] = "1"; + } return forwarded; } diff --git a/packages/tunnel-client/src/index.ts b/packages/tunnel-client/src/index.ts index 33840ab17f..e523e4080b 100644 --- a/packages/tunnel-client/src/index.ts +++ b/packages/tunnel-client/src/index.ts @@ -1,6 +1,7 @@ export type { TunnelClientLogger } from "./logger.js"; export { headersForLoopbackRequest, + TUNNEL_ORIGIN_HEADER, type LoopbackHeaderRewrite, } from "./headers.js"; export { humanizeTransportError } from "./humanize.js"; diff --git a/packages/tunnel-client/src/session.ts b/packages/tunnel-client/src/session.ts index 2f12fb3e46..beb22eebfa 100644 --- a/packages/tunnel-client/src/session.ts +++ b/packages/tunnel-client/src/session.ts @@ -234,6 +234,7 @@ export class TunnelSession { const headers = headersForLoopbackRequest(meta.headers, { publicOrigin: resolved.publicOrigin, loopbackOrigin: new URL(resolved.origin).origin, + markTunnelOrigin: true, ...(resolved.host !== undefined ? { host: resolved.host } : {}), }); try { @@ -304,6 +305,7 @@ export class TunnelSession { const headers = headersForLoopbackRequest(frame.headers, { publicOrigin: resolved.publicOrigin, loopbackOrigin: new URL(resolved.origin).origin, + markTunnelOrigin: true, ...(resolved.host !== undefined ? { host: resolved.host } : {}), }); const countsAsRemoteClient = isBareBbRealtimeWs(frame.path, frame.target); diff --git a/packages/tunnel-client/test/headers.test.ts b/packages/tunnel-client/test/headers.test.ts new file mode 100644 index 0000000000..dfd582066f --- /dev/null +++ b/packages/tunnel-client/test/headers.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from "vitest"; +import { + headersForLoopbackRequest, + TUNNEL_ORIGIN_HEADER, +} from "../src/headers.js"; + +describe("headersForLoopbackRequest", () => { + it("strips a client-supplied tunnel marker and stamps the trusted marker", () => { + const headers = headersForLoopbackRequest( + [ + ["X-BB-Via-Tunnel", "client-controlled"], + ["x-bb-via-tunnel", "0"], + ["content-type", "application/json"], + ], + { + publicOrigin: "https://owner.getbb.app", + loopbackOrigin: "http://127.0.0.1:38886", + markTunnelOrigin: true, + }, + ); + + expect(headers).toEqual({ + "content-type": "application/json", + [TUNNEL_ORIGIN_HEADER]: "1", + }); + }); + + it("stamps both ordinary HTTP requests and websocket upgrade headers", () => { + expect( + headersForLoopbackRequest([], { + publicOrigin: "https://owner.getbb.app", + loopbackOrigin: "http://127.0.0.1:38886", + markTunnelOrigin: true, + }), + ).toEqual({ [TUNNEL_ORIGIN_HEADER]: "1" }); + }); +}); From d7c0a7968a7ae4bd68c516243446a43abb491030 Mon Sep 17 00:00:00 2001 From: Sawyer Hood Date: Sat, 18 Jul 2026 10:39:33 -0700 Subject: [PATCH 6/8] Multiplayer wave 4: fix gpt-5.6 review findings High findings: - Member management is now blocked at the connect gate for all forwarded visitor traffic (HTTP and ws-upgrade paths), so tunnels opened by pre-marker clients can no longer reach /api/v1/members; the local x-bb-via-tunnel check remains as defense in depth. - Membership mutations commit atomically with their audit rows (D1 batch, transaction fallback for the sqlite test double); a failed audit write leaves membership unchanged. - The speaker gate counts only attributed client/turn/requested events, so a manual stop by a second person no longer flips a single-author thread out of byte-identical provider input (covered by events_thread_type_sequence_idx, no new index). Medium findings: - Provider resolve, plugin respond, and cancel persist the first resolver's handle in the same conditional status transition; racing duplicates cannot overwrite it. - Typing TTLs are per socket, derived per handle, so one device stopping no longer clears a person's typing from their other device. - The app rebinds the live websocket when the claimed identity is saved, edited, or cleared (same socket, reconnect + resubscribe + reseed). - The presence store guards its reconnect snapshot with a generation counter so in-flight snapshots cannot clobber newer realtime updates or removals. Co-Authored-By: Claude Fable 5 --- apps/app/src/lib/presence-store.test.ts | 59 +++++- apps/app/src/lib/presence-store.ts | 72 +++++-- apps/app/src/lib/ws.identity-rebind.test.ts | 189 ++++++++++++++++++ apps/app/src/lib/ws.ts | 23 ++- apps/connect/src/members.test.ts | 52 +++++ apps/connect/src/members.ts | 150 +++++++++----- apps/connect/src/worker.test.ts | 64 ++++++ apps/connect/src/worker.ts | 18 ++ .../server/src/routes/threads/interactions.ts | 8 +- .../interactions/pending-interactions.ts | 16 ++ apps/server/src/services/presence.ts | 41 ++-- apps/server/test/app/presence.test.ts | 66 ++++++ .../public/public-thread-interactions.test.ts | 122 +++++++++++ .../services/threads/thread-speaker.test.ts | 51 ++++- packages/db/src/data/events.ts | 1 + packages/db/src/data/index.ts | 1 - packages/db/src/data/pending-interactions.ts | 40 ++-- packages/db/test/data/events.test.ts | 38 ++-- .../db/test/data/pending-interactions.test.ts | 15 +- 19 files changed, 889 insertions(+), 137 deletions(-) create mode 100644 apps/app/src/lib/ws.identity-rebind.test.ts diff --git a/apps/app/src/lib/presence-store.test.ts b/apps/app/src/lib/presence-store.test.ts index 2c9249d644..fdff19e03a 100644 --- a/apps/app/src/lib/presence-store.test.ts +++ b/apps/app/src/lib/presence-store.test.ts @@ -42,7 +42,8 @@ describe("PresenceStore", () => { store.setThreadViewers("thr_stale", [viewer("alice")]); store.patchSummary({ thr_stale: ["alice"] }); - store.replaceAll({ thr_live: [viewer("bob", true)] }); + const generation = store.beginSnapshot(); + store.applySnapshot({ thr_live: [viewer("bob", true)] }, generation); expect(store.getThreadViewers("thr_stale")).toEqual([]); expect(store.getSummaryHandles("thr_stale")).toEqual([]); @@ -53,6 +54,62 @@ describe("PresenceStore", () => { expect(store.getSummaryHandles("thr_live")).toEqual(["bob"]); }); + it("does not let an in-flight snapshot clobber a newer realtime update", () => { + const store = new PresenceStore(); + const generation = store.beginSnapshot(); + // Arrives while the snapshot request is still in flight. + store.setThreadViewers("thr_1", [viewer("carol", true)]); + store.patchSummary({ thr_1: ["carol"] }); + + // The (older) snapshot resolves afterward with stale data for thr_1. + store.applySnapshot( + { thr_1: [viewer("alice")], thr_2: [viewer("bob")] }, + generation, + ); + + expect(store.getThreadViewers("thr_1").map((v) => v.handle)).toEqual([ + "carol", + ]); + expect(store.getSummaryHandles("thr_1")).toEqual(["carol"]); + // Untouched threads still seed from the snapshot. + expect(store.getThreadViewers("thr_2").map((v) => v.handle)).toEqual([ + "bob", + ]); + expect(store.getSummaryHandles("thr_2")).toEqual(["bob"]); + }); + + it("does not let an in-flight snapshot resurrect a realtime removal", () => { + const store = new PresenceStore(); + store.setThreadViewers("thr_1", [viewer("alice")]); + store.patchSummary({ thr_1: ["alice"] }); + + const generation = store.beginSnapshot(); + // The viewer leaves while the snapshot request is still in flight. + store.setThreadViewers("thr_1", []); + store.patchSummary({ thr_1: [] }); + + // The (older) snapshot still lists the departed viewer. + store.applySnapshot({ thr_1: [viewer("alice")] }, generation); + + expect(store.getThreadViewers("thr_1")).toEqual([]); + expect(store.getSummaryHandles("thr_1")).toEqual([]); + }); + + it("guards viewer rosters and summaries independently", () => { + const store = new PresenceStore(); + const generation = store.beginSnapshot(); + // Only the summary is touched while the snapshot is in flight. + store.patchSummary({ thr_1: ["carol"] }); + + store.applySnapshot({ thr_1: [viewer("alice")] }, generation); + + // The untouched roster seeds from the snapshot; the touched summary wins. + expect(store.getThreadViewers("thr_1").map((v) => v.handle)).toEqual([ + "alice", + ]); + expect(store.getSummaryHandles("thr_1")).toEqual(["carol"]); + }); + it("returns a stable reference for an unchanged roster", () => { const store = new PresenceStore(); store.setThreadViewers("thr_1", [viewer("alice")]); diff --git a/apps/app/src/lib/presence-store.ts b/apps/app/src/lib/presence-store.ts index 8751a6c967..d4c0d41b31 100644 --- a/apps/app/src/lib/presence-store.ts +++ b/apps/app/src/lib/presence-store.ts @@ -23,6 +23,14 @@ export class PresenceStore { private viewersByThreadId = new Map(); private summaryHandlesByThreadId = new Map(); private listeners = new Set<() => void>(); + // Ordering guard for the async snapshot: every applied realtime message + // bumps `generation` and stamps the thread ids it touched. The snapshot + // captures the generation before its HTTP request and, when it resolves, + // skips any thread a newer realtime message already updated or removed — + // live broadcasts always beat the older snapshot. + private generation = 0; + private viewerTouchGeneration = new Map(); + private summaryTouchGeneration = new Map(); attach(manager: WebSocketManager): () => void { const unsubscribePresence = manager.onThreadPresence((message) => { @@ -42,6 +50,7 @@ export class PresenceStore { } private async seedFromSnapshot(): Promise { + const sinceGeneration = this.beginSnapshot(); let snapshot: PresenceSnapshotResponse; try { snapshot = await request( @@ -51,24 +60,59 @@ export class PresenceStore { // Presence is cosmetic; a failed seed just waits for live broadcasts. return; } - this.replaceAll(snapshot.threads); + this.applySnapshot(snapshot.threads, sinceGeneration); } - /** Full-state replace from the HTTP snapshot (complete current rosters). */ - replaceAll( + /** Capture before requesting a snapshot; pass the result to applySnapshot. */ + beginSnapshot(): number { + return this.generation; + } + + /** + * Apply the HTTP snapshot (complete current rosters): flush entries absent + * from it and replace the rest — except threads a realtime message touched + * after `sinceGeneration`, whose newer live state (including removal) wins. + */ + applySnapshot( threads: Record, + sinceGeneration: number, ): void { - this.viewersByThreadId = new Map(); - this.summaryHandlesByThreadId = new Map(); + const untouched = (touches: Map, threadId: string) => + (touches.get(threadId) ?? 0) <= sinceGeneration; + for (const threadId of [...this.viewersByThreadId.keys()]) { + if ( + !(threadId in threads) && + untouched(this.viewerTouchGeneration, threadId) + ) { + this.viewersByThreadId.delete(threadId); + } + } + for (const threadId of [...this.summaryHandlesByThreadId.keys()]) { + if ( + !(threadId in threads) && + untouched(this.summaryTouchGeneration, threadId) + ) { + this.summaryHandlesByThreadId.delete(threadId); + } + } for (const [threadId, viewers] of Object.entries(threads)) { - if (viewers.length === 0) { - continue; + if (untouched(this.viewerTouchGeneration, threadId)) { + if (viewers.length === 0) { + this.viewersByThreadId.delete(threadId); + } else { + this.viewersByThreadId.set(threadId, viewers); + } + } + if (untouched(this.summaryTouchGeneration, threadId)) { + if (viewers.length === 0) { + this.summaryHandlesByThreadId.delete(threadId); + } else { + this.summaryHandlesByThreadId.set( + threadId, + viewers.map((viewer) => viewer.handle), + ); + } } - this.viewersByThreadId.set(threadId, viewers); - this.summaryHandlesByThreadId.set( - threadId, - viewers.map((viewer) => viewer.handle), - ); } this.notify(); } @@ -77,6 +121,8 @@ export class PresenceStore { threadId: string, viewers: readonly PresenceViewer[], ): void { + this.generation += 1; + this.viewerTouchGeneration.set(threadId, this.generation); if (viewers.length === 0) { this.viewersByThreadId.delete(threadId); } else { @@ -86,7 +132,9 @@ export class PresenceStore { } patchSummary(threads: Record): void { + this.generation += 1; for (const [threadId, handles] of Object.entries(threads)) { + this.summaryTouchGeneration.set(threadId, this.generation); if (handles.length === 0) { this.summaryHandlesByThreadId.delete(threadId); } else { diff --git a/apps/app/src/lib/ws.identity-rebind.test.ts b/apps/app/src/lib/ws.identity-rebind.test.ts new file mode 100644 index 0000000000..f624c5e7f9 --- /dev/null +++ b/apps/app/src/lib/ws.identity-rebind.test.ts @@ -0,0 +1,189 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +// Fake socket that records its URL provider and reconnect() calls so the +// tests can assert the identity rides the next upgrade URL. +const fakeSocketState = vi.hoisted(() => { + type UrlProvider = () => string; + + class FakeReconnectingWebSocket { + onclose: (() => void) | null = null; + onmessage: ((event: MessageEvent) => void) | null = null; + onopen: (() => void) | null = null; + readyState = 1; + readonly sentMessages: string[] = []; + reconnectCalls = 0; + private readonly urlProvider: UrlProvider; + + constructor(urlProvider: UrlProvider) { + this.urlProvider = urlProvider; + instances.push(this); + } + + close(): void { + this.readyState = 3; + this.onclose?.(); + } + + open(): void { + this.readyState = 1; + this.onopen?.(); + } + + send(data: string): void { + this.sentMessages.push(data); + } + + reconnect(): void { + this.reconnectCalls += 1; + this.close(); + this.open(); + } + + nextUpgradeUrl(): string { + return this.urlProvider(); + } + } + + const instances: FakeReconnectingWebSocket[] = []; + + return { FakeReconnectingWebSocket, instances }; +}); + +// Controllable claimed-identity fake: the real store suppresses identities on +// localhost (the test origin), so the manager's rebind path could never fire. +const identityState = vi.hoisted(() => { + const state = { + value: null as string | null, + listeners: new Set<() => void>(), + set(next: string | null): void { + state.value = next; + for (const listener of state.listeners) { + listener(); + } + }, + }; + return state; +}); + +vi.mock("partysocket/ws", () => ({ + default: fakeSocketState.FakeReconnectingWebSocket, +})); + +vi.mock("./dev-websocket-url", () => ({ + buildDevWebSocketUrl: () => "ws://bb.test/ws", +})); + +vi.mock("./claimed-identity-store", () => ({ + getClaimedIdentityHeaderValue: () => identityState.value, + subscribeClaimedIdentity: (listener: () => void) => { + identityState.listeners.add(listener); + return () => { + identityState.listeners.delete(listener); + }; + }, +})); + +import { WebSocketManager } from "./ws"; + +function getOnlySocket() { + const socket = fakeSocketState.instances[0]; + if (!socket) { + throw new Error("Expected websocket to be created"); + } + return socket; +} + +describe("WebSocketManager claimed-identity rebind", () => { + const originalWebSocket = globalThis.WebSocket; + + beforeEach(() => { + fakeSocketState.instances.length = 0; + identityState.value = null; + identityState.listeners.clear(); + Object.defineProperty(globalThis, "WebSocket", { + configurable: true, + value: { OPEN: 1 }, + }); + }); + + afterEach(() => { + Object.defineProperty(globalThis, "WebSocket", { + configurable: true, + value: originalWebSocket, + }); + }); + + it("reconnects exactly once when an identity is claimed, with ?identity= on the next URL", () => { + const manager = new WebSocketManager(); + manager.connect(); + const socket = getOnlySocket(); + socket.open(); + + expect(socket.nextUpgradeUrl()).toBe("ws://bb.test/ws"); + + identityState.set("alice-encoded"); + + expect(socket.reconnectCalls).toBe(1); + expect(fakeSocketState.instances).toHaveLength(1); + expect(socket.nextUpgradeUrl()).toBe( + "ws://bb.test/ws?identity=alice-encoded", + ); + }); + + it("rebinds again on edit and drops ?identity= on clear", () => { + const manager = new WebSocketManager(); + manager.connect(); + const socket = getOnlySocket(); + socket.open(); + + identityState.set("alice-encoded"); + identityState.set("alice+cooper"); + expect(socket.reconnectCalls).toBe(2); + expect(socket.nextUpgradeUrl()).toBe( + "ws://bb.test/ws?identity=alice%2Bcooper", + ); + + identityState.set(null); + expect(socket.reconnectCalls).toBe(3); + expect(socket.nextUpgradeUrl()).toBe("ws://bb.test/ws"); + }); + + it("ignores store notifications that leave the identity unchanged", () => { + const manager = new WebSocketManager(); + manager.connect(); + const socket = getOnlySocket(); + socket.open(); + + identityState.set(null); + identityState.set(null); + + expect(socket.reconnectCalls).toBe(0); + }); + + it("resubscribes active targets over the rebound socket", () => { + const manager = new WebSocketManager(); + manager.connect(); + const socket = getOnlySocket(); + socket.open(); + manager.subscribe({ kind: "project-list" }); + socket.sentMessages.length = 0; + + identityState.set("alice-encoded"); + + expect( + socket.sentMessages.map((message) => JSON.parse(message) as unknown), + ).toEqual([{ type: "subscribe", target: { kind: "project-list" } }]); + }); + + it("stops listening for identity changes after disconnect", () => { + const manager = new WebSocketManager(); + manager.connect(); + const socket = getOnlySocket(); + socket.open(); + manager.disconnect(); + + identityState.set("alice-encoded"); + + expect(socket.reconnectCalls).toBe(0); + }); +}); diff --git a/apps/app/src/lib/ws.ts b/apps/app/src/lib/ws.ts index a2a5504194..26b3e01fcf 100644 --- a/apps/app/src/lib/ws.ts +++ b/apps/app/src/lib/ws.ts @@ -20,7 +20,10 @@ import type { ThreadPresenceMessage, } from "@bb/server-contract"; import { buildDevWebSocketUrl } from "./dev-websocket-url"; -import { getClaimedIdentityHeaderValue } from "./claimed-identity-store"; +import { + getClaimedIdentityHeaderValue, + subscribeClaimedIdentity, +} from "./claimed-identity-store"; type ChangeCallback = (message: ChangedMessage) => void; type ThreadOpenCallback = (signal: ThreadOpenSignal) => void; @@ -57,6 +60,8 @@ export class WebSocketManager { private connectionStateCallbacks = new Set(); private hasConnected = false; private connectionState: WebSocketConnectionState = "connecting"; + private unsubscribeIdentity: (() => void) | null = null; + private lastIdentityHeaderValue: string | null = null; connect(): void { if (this.socket) return; @@ -107,6 +112,20 @@ export class WebSocketManager { this.hasConnected ? "reconnecting" : "connecting", ); }; + + // The claimed identity is bound at upgrade time via ?identity=, so a + // save/edit/clear after connect must rebind the live socket. Reconnect + // through partysocket's own machinery: the URL provider re-reads the + // identity, and onopen re-subscribes and reseeds presence as usual. + this.lastIdentityHeaderValue = getClaimedIdentityHeaderValue(); + this.unsubscribeIdentity = subscribeClaimedIdentity(() => { + const next = getClaimedIdentityHeaderValue(); + if (next === this.lastIdentityHeaderValue) { + return; + } + this.lastIdentityHeaderValue = next; + this.socket?.reconnect(); + }); } /** @@ -191,6 +210,8 @@ export class WebSocketManager { } disconnect(): void { + this.unsubscribeIdentity?.(); + this.unsubscribeIdentity = null; if (this.socket) { this.socket.close(); this.socket = null; diff --git a/apps/connect/src/members.test.ts b/apps/connect/src/members.test.ts index 7fd6ebfd41..6f0aa93a12 100644 --- a/apps/connect/src/members.test.ts +++ b/apps/connect/src/members.test.ts @@ -16,9 +16,11 @@ import { } from "@bb/connect-db"; import { + addServerMember, admitServerMember, handleServerMembersWithDb, matchServerMembersRoute, + removeServerMember, } from "./members.js"; const MIGRATIONS_DIR = fileURLToPath( @@ -459,6 +461,56 @@ describe("owner member-management API", () => { ); expect(response.status).toBe(404); }); + + it("rolls back an added member when its audit insert fails", async () => { + sqlite.exec("DROP TABLE audit_log"); + + await expect( + addServerMember( + db, + "server-1", + "owner-user", + "invited", + NOW, + ), + ).rejects.toThrow(/audit_log/iu); + expect( + db + .select() + .from(serverMember) + .where(eq(serverMember.serverId, "server-1")) + .all(), + ).toEqual([]); + }); + + it("rolls back a removed member when its audit insert fails", async () => { + db.insert(serverMember) + .values({ + serverId: "server-1", + userId: "member-user", + addedByUserId: "owner-user", + createdAt: NOW, + }) + .run(); + sqlite.exec("DROP TABLE audit_log"); + + await expect( + removeServerMember( + db, + "server-1", + "owner-user", + "member-user", + NOW, + ), + ).rejects.toThrow(/audit_log/iu); + expect( + db + .select({ userId: serverMember.userId }) + .from(serverMember) + .where(eq(serverMember.serverId, "server-1")) + .all(), + ).toEqual([{ userId: "member-user" }]); + }); }); describe("member gate admission audit", () => { diff --git a/apps/connect/src/members.ts b/apps/connect/src/members.ts index 3013b46019..646bd0b446 100644 --- a/apps/connect/src/members.ts +++ b/apps/connect/src/members.ts @@ -1,4 +1,5 @@ -import { and, asc, eq } from "drizzle-orm"; +import { and, asc, eq, sql } from "drizzle-orm"; +import type { BatchItem } from "drizzle-orm/batch"; import { drizzle } from "drizzle-orm/d1"; import { auditLog, @@ -46,6 +47,19 @@ type AddServerMemberResult = reason: "already-member" | "cannot-add-owner" | "unknown-handle"; }; +interface AtomicBatchDb { + batch( + queries: readonly [BatchItem<"sqlite">, BatchItem<"sqlite">], + ): Promise; +} + +interface MemberAuditValues { + userId: string; + action: "member-added" | "member-admitted" | "member-removed"; + detail: Record; + createdAt: Date; +} + function jsonError(error: string, status: number): Response { return Response.json({ error }, { status }); } @@ -73,25 +87,25 @@ function affectedRows(result: unknown): number { throw new Error("server member mutation did not report affected rows"); } +function supportsAtomicBatch(db: ConnectDb): db is ConnectDb & AtomicBatchDb { + return "batch" in db && typeof db.batch === "function"; +} + +function auditLogValues(values: MemberAuditValues) { + return { + id: crypto.randomUUID(), + userId: values.userId, + action: values.action, + detail: JSON.stringify(values.detail), + createdAt: values.createdAt, + }; +} + async function appendAuditLog( db: ConnectDb, - values: { - userId: string; - action: "member-added" | "member-admitted" | "member-removed"; - detail: Record; - createdAt: Date; - }, + values: MemberAuditValues, ): Promise { - await db - .insert(auditLog) - .values({ - id: crypto.randomUUID(), - userId: values.userId, - action: values.action, - detail: JSON.stringify(values.detail), - createdAt: values.createdAt, - }) - .run(); + await db.insert(auditLog).values(auditLogValues(values)).run(); } /** Parse the owner member-management API path before host routing. */ @@ -220,28 +234,37 @@ export async function addServerMember( } try { - await db - .insert(serverMember) - .values({ - serverId, - userId: target.userId, - addedByUserId: ownerUserId, + const memberInsert = db.insert(serverMember).values({ + serverId, + userId: target.userId, + addedByUserId: ownerUserId, + createdAt: now, + }); + const auditInsert = db.insert(auditLog).values( + auditLogValues({ + userId: ownerUserId, + action: "member-added", + detail: { serverId, memberUserId: target.userId }, createdAt: now, - }) - .run(); + }), + ); + if (supportsAtomicBatch(db)) { + await db.batch([memberInsert, auditInsert]); + } else { + // better-sqlite3 (used by the in-memory tests) has no batch method. Its + // transaction callback and statements are synchronous, giving the same + // all-or-nothing behavior as D1's implicit batch transaction. + await db.transaction(() => { + memberInsert.run(); + auditInsert.run(); + }); + } } catch (error) { if (isUniqueConstraintError(error)) { return { ok: false, reason: "already-member" }; } throw error; } - - await appendAuditLog(db, { - userId: ownerUserId, - action: "member-added", - detail: { serverId, memberUserId: target.userId }, - createdAt: now, - }); return { ok: true, member: { @@ -262,24 +285,53 @@ export async function removeServerMember( memberUserId: string, now: Date = new Date(), ): Promise { - const result = await db - .delete(serverMember) - .where( - and( - eq(serverMember.serverId, serverId), - eq(serverMember.userId, memberUserId), - ), - ) - .run(); - if (affectedRows(result) === 0) return false; - - await appendAuditLog(db, { - userId: ownerUserId, - action: "member-removed", - detail: { serverId, memberUserId }, - createdAt: now, + const membershipFilter = and( + eq(serverMember.serverId, serverId), + eq(serverMember.userId, memberUserId), + ); + if (supportsAtomicBatch(db)) { + const auditId = crypto.randomUUID(); + const action = "member-removed"; + const detail = JSON.stringify({ serverId, memberUserId }); + // Insert the audit row only when the member exists, then delete it in the + // same D1 batch. This preserves the absent-member 404 without opening a + // race between an existence check and the atomic mutation. + const conditionalAuditInsert = db.insert(auditLog).select((qb) => + qb + .select({ + id: sql`${auditId}`.as("id"), + userId: sql`${ownerUserId}`.as("user_id"), + action: sql`${action}`.as("action"), + detail: sql`${detail}`.as("detail"), + ipAddress: sql`null`.as("ip_address"), + createdAt: sql`${now.getTime()}`.as("created_at"), + }) + .from(serverMember) + .where(membershipFilter) + .limit(1), + ); + const memberDelete = db.delete(serverMember).where(membershipFilter); + const results = await db.batch([conditionalAuditInsert, memberDelete]); + return affectedRows(results[1]) > 0; + } + + // See the add path above: this branch is the synchronous better-sqlite3 + // test double, whose transaction rolls the delete back if auditing fails. + return await db.transaction((tx) => { + const result = tx.delete(serverMember).where(membershipFilter).run(); + if (affectedRows(result) === 0) return false; + tx.insert(auditLog) + .values( + auditLogValues({ + userId: ownerUserId, + action: "member-removed", + detail: { serverId, memberUserId }, + createdAt: now, + }), + ) + .run(); + return true; }); - return true; } async function resolveOwnerSessionUserId( diff --git a/apps/connect/src/worker.test.ts b/apps/connect/src/worker.test.ts index 66110eee71..8320b165c6 100644 --- a/apps/connect/src/worker.test.ts +++ b/apps/connect/src/worker.test.ts @@ -933,6 +933,70 @@ describe("gate worker share hosts", () => { expect(captured).toHaveLength(1); }); + it.each([ + ["owner", OWNER, "GET", "/api/v1/members"], + ["owner", OWNER, "POST", "/api/v1/members"], + ["owner", OWNER, "DELETE", "/api/v1/members/user-member"], + ["member", OTHER, "GET", "/api/v1/members"], + ["member", OTHER, "POST", "/api/v1/members"], + ["member", OTHER, "DELETE", "/api/v1/members/user-member"], + ] as const)( + "blocks %s visitor %s %s before the tunnel", + async (_sessionKind, sessionUserId, method, path) => { + mockVerifySession.mockResolvedValue(sessionUserId); + if (sessionUserId === OTHER) mockAdmitServerMember.mockResolvedValue(true); + const { env, ctx, captured } = makeEnv(() => new Response("origin")); + + const response = await worker.fetch( + visitorRequest("sawyer.getbb.app", path, { method }), + env as never, + ctx, + ); + + expect(response.status).toBe(403); + await expect(response.json()).resolves.toEqual({ + error: "member management is only available from the owner console", + }); + expect(captured).toHaveLength(0); + expect(mockServeWithCache).not.toHaveBeenCalled(); + }, + ); + + it("blocks member-management websocket upgrades before the tunnel", async () => { + const { env, ctx, captured } = makeEnv(() => new Response("upgraded")); + const response = await worker.fetch( + visitorRequest("sawyer.getbb.app", "/api/v1/members/live", { + headers: { upgrade: "websocket" }, + }), + env as never, + ctx, + ); + + expect(response.status).toBe(403); + expect(captured).toHaveLength(0); + }); + + it.each([ + ["owner", OWNER], + ["member", OTHER], + ] as const)( + "continues forwarding unrelated /api/v1 paths for a %s visitor", + async (_sessionKind, sessionUserId) => { + mockVerifySession.mockResolvedValue(sessionUserId); + if (sessionUserId === OTHER) mockAdmitServerMember.mockResolvedValue(true); + const { env, ctx, captured } = makeEnv(() => new Response("origin")); + + const response = await worker.fetch( + visitorRequest("sawyer.getbb.app", "/api/v1/threads"), + env as never, + ctx, + ); + + expect(response.status).toBe(200); + expect(captured).toHaveLength(1); + }, + ); + it("does not treat a desktop cookie as member identity", async () => { mockParseCookie.mockImplementation((_header, name) => name === DESKTOP_SESSION_COOKIE ? "desktop-token" : null, diff --git a/apps/connect/src/worker.ts b/apps/connect/src/worker.ts index 376bd42e00..2be69f029f 100644 --- a/apps/connect/src/worker.ts +++ b/apps/connect/src/worker.ts @@ -250,6 +250,13 @@ function isHostManagementMutation(request: Request, pathname: string): boolean { ); } +function isLocalMemberManagementPath(pathname: string): boolean { + return ( + pathname === "/api/v1/members" || + pathname.startsWith("/api/v1/members/") + ); +} + /** Cache namespace for a resolved routing key plus optional share target. */ export function cacheNamespace( routingKey: string, @@ -440,6 +447,17 @@ export default { if (!isMember) return text("bb connect: not your server\n", 403); } + // Member management is deliberately local owner-console functionality. + // Enforce that at the gate so even tunnels opened by pre-marker clients + // cannot forward this surface to the local server. This also precedes the + // WebSocket branch below, so an upgrade cannot bypass the same boundary. + if (isLocalMemberManagementPath(url.pathname)) { + return Response.json( + { error: "member management is only available from the owner console" }, + { status: 403 }, + ); + } + const doRequest = requestForTunnelDo(request, target, "session"); // WebSocket upgrades (bb's /ws, terminals) can't be cached — proxy directly. diff --git a/apps/server/src/routes/threads/interactions.ts b/apps/server/src/routes/threads/interactions.ts index eecbf2afed..4e28f5dd5c 100644 --- a/apps/server/src/routes/threads/interactions.ts +++ b/apps/server/src/routes/threads/interactions.ts @@ -4,7 +4,6 @@ import { type PublicApiSchema, } from "@bb/server-contract"; import type { Context, Hono } from "hono"; -import { setPendingInteractionResolvedByHandle } from "@bb/db"; import { z } from "zod"; import type { AppDeps } from "../../types.js"; import { ApiError } from "../../errors.js"; @@ -62,14 +61,11 @@ export function registerThreadInteractionRoutes( context.req.param("interactionId"), ); const interaction = deps.pendingInteractions.resolvePendingInteraction({ + actorHandle: getRequestActor(context as unknown as Context).handle, threadId: thread.id, interactionId, resolution: payload, }); - setPendingInteractionResolvedByHandle(deps.db, { - id: interactionId, - resolvedByHandle: getRequestActor(context as unknown as Context).handle, - }); return context.json(interaction); }); @@ -84,6 +80,7 @@ export function registerThreadInteractionRoutes( } return context.json( deps.pendingInteractions.respondToPluginInteraction({ + actorHandle: getRequestActor(context as unknown as Context).handle, threadId: thread.id, interactionId: parsePendingInteractionId( context.req.param("interactionId"), @@ -97,6 +94,7 @@ export function registerThreadInteractionRoutes( const thread = requirePublicThread(deps.db, context.req.param("id")); return context.json( deps.pendingInteractions.cancelPluginInteraction({ + actorHandle: getRequestActor(context as unknown as Context).handle, threadId: thread.id, interactionId: parsePendingInteractionId( context.req.param("interactionId"), diff --git a/apps/server/src/services/interactions/pending-interactions.ts b/apps/server/src/services/interactions/pending-interactions.ts index c4a094a0e7..3d9533969d 100644 --- a/apps/server/src/services/interactions/pending-interactions.ts +++ b/apps/server/src/services/interactions/pending-interactions.ts @@ -69,12 +69,14 @@ interface RegisterPendingInteractionArgs { } interface ResolvePendingInteractionArgs { + actorHandle?: string; interactionId: string; resolution: PendingInteractionResolution; threadId: string; } interface QueueInteractionResolutionCommandArgs { + actorHandle?: string; interaction: PendingInteraction; resolution: PendingInteractionResolution; } @@ -525,6 +527,7 @@ export class PendingInteractionLifecycle { } respondToPluginInteraction(args: { + actorHandle?: string; interactionId: string; threadId: string; value: JsonValue; @@ -537,6 +540,9 @@ export class PendingInteractionLifecycle { const updated = setPendingInteractionResolved(this.deps.db, { id: current.id, resolution: JSON.stringify({ kind: "plugin_submitted" }), + ...(args.actorHandle === undefined + ? {} + : { resolvedByHandle: args.actorHandle }), }); if (!updated) throw buildResolveConflictError(this.requireInteraction(current.id)); @@ -550,6 +556,7 @@ export class PendingInteractionLifecycle { } cancelPluginInteraction(args: { + actorHandle?: string; interactionId: string; threadId: string; reason: PluginInteractionCancelReason; @@ -563,6 +570,9 @@ export class PendingInteractionLifecycle { } const updated = setPendingInteractionInterrupted(this.deps.db, { id: current.id, + ...(args.actorHandle === undefined + ? {} + : { resolvedByHandle: args.actorHandle }), statusReason: args.reason, }); if (!updated) @@ -610,6 +620,9 @@ export class PendingInteractionLifecycle { validatePendingInteractionResolution(current, args.resolution); const updated = this.queueInteractionResolutionCommand({ + ...(args.actorHandle === undefined + ? {} + : { actorHandle: args.actorHandle }), interaction: current, resolution: args.resolution, }); @@ -818,6 +831,9 @@ export class PendingInteractionLifecycle { const resolving = setPendingInteractionResolving(tx, { id: args.interaction.id, resolution: resolutionJson, + ...(args.actorHandle === undefined + ? {} + : { resolvedByHandle: args.actorHandle }), }); if (resolving) { return resolving; diff --git a/apps/server/src/services/presence.ts b/apps/server/src/services/presence.ts index 9e3ac7c9bc..8eacd54b7d 100644 --- a/apps/server/src/services/presence.ts +++ b/apps/server/src/services/presence.ts @@ -5,8 +5,7 @@ export const PRESENCE_TYPING_TTL_MS = 6_000; interface ViewerState { actorsBySocket: Map; - typing: boolean; - typingTimeout: ReturnType | null; + typingTimeoutsBySocket: Map>; } interface PresenceServiceArgs { @@ -61,8 +60,7 @@ export class PresenceService { this.viewersByThread.get(threadId) ?? new Map(); const viewer = viewers.get(actor.handle) ?? { actorsBySocket: new Map(), - typing: false, - typingTimeout: null, + typingTimeoutsBySocket: new Map>(), }; viewer.actorsBySocket.set(socket, actor); viewers.set(actor.handle, viewer); @@ -89,9 +87,9 @@ export class PresenceService { if (viewer === undefined || viewers === undefined) { return; } + this.clearSocketTyping(viewer, socket); viewer.actorsBySocket.delete(socket); if (viewer.actorsBySocket.size === 0) { - this.clearTypingTimeout(viewer); viewers.delete(handle); } if (viewers.size === 0) { @@ -110,26 +108,26 @@ export class PresenceService { return; } - this.clearTypingTimeout(viewer); + const wasTyping = viewer.typingTimeoutsBySocket.size > 0; + this.clearSocketTyping(viewer, socket); if (!typing) { - if (viewer.typing) { - viewer.typing = false; + if (wasTyping && viewer.typingTimeoutsBySocket.size === 0) { this.emitIfChanged(threadId); } return; } - const wasTyping = viewer.typing; - viewer.typing = true; - viewer.typingTimeout = setTimeout(() => { - viewer.typingTimeout = null; - if (!viewer.typing) { + const typingTimeout = setTimeout(() => { + if (viewer.typingTimeoutsBySocket.get(socket) !== typingTimeout) { return; } - viewer.typing = false; - this.emitIfChanged(threadId); + viewer.typingTimeoutsBySocket.delete(socket); + if (viewer.typingTimeoutsBySocket.size === 0) { + this.emitIfChanged(threadId); + } }, this.typingTtlMs); - viewer.typingTimeout.unref(); + typingTimeout.unref(); + viewer.typingTimeoutsBySocket.set(socket, typingTimeout); if (!wasTyping) { this.emitIfChanged(threadId); @@ -147,12 +145,13 @@ export class PresenceService { return { threads }; } - private clearTypingTimeout(viewer: ViewerState): void { - if (viewer.typingTimeout === null) { + private clearSocketTyping(viewer: ViewerState, socket: object): void { + const typingTimeout = viewer.typingTimeoutsBySocket.get(socket); + if (typingTimeout === undefined) { return; } - clearTimeout(viewer.typingTimeout); - viewer.typingTimeout = null; + clearTimeout(typingTimeout); + viewer.typingTimeoutsBySocket.delete(socket); } private emitIfChanged(threadId: string): boolean { @@ -181,7 +180,7 @@ export class PresenceService { handle, displayName: actor.displayName, imageUrl: actor.imageUrl, - typing: viewer.typing, + typing: viewer.typingTimeoutsBySocket.size > 0, }; }); } diff --git a/apps/server/test/app/presence.test.ts b/apps/server/test/app/presence.test.ts index d4b521b32d..aabbec7a58 100644 --- a/apps/server/test/app/presence.test.ts +++ b/apps/server/test/app/presence.test.ts @@ -213,6 +213,72 @@ describe("thread presence", () => { releaseSocketActor(detailSocket); }); + it("keeps a handle typing while another socket remains explicitly active", () => { + const hub = new NotificationHub(); + const firstSocket = createMockHubSocket(); + const secondSocket = createMockHubSocket(); + registerSocketActor(firstSocket, sawyer); + registerSocketActor(secondSocket, { ...sawyer, clientId: "browser-2" }); + hub.subscribe(firstSocket, { + kind: "thread-detail", + threadId: "thread-1", + }); + hub.subscribe(secondSocket, { + kind: "thread-detail", + threadId: "thread-1", + }); + + hub.setTyping(firstSocket, "thread-1", true); + hub.setTyping(secondSocket, "thread-1", true); + hub.setTyping(firstSocket, "thread-1", false); + expect(hub.getPresenceSnapshot().threads["thread-1"]?.[0]?.typing).toBe( + true, + ); + + hub.setTyping(secondSocket, "thread-1", false); + expect(hub.getPresenceSnapshot().threads["thread-1"]?.[0]?.typing).toBe( + false, + ); + hub.unregisterClient(firstSocket); + hub.unregisterClient(secondSocket); + releaseSocketActor(firstSocket); + releaseSocketActor(secondSocket); + }); + + it("keeps a handle typing when one socket TTL expires before another", async () => { + vi.useFakeTimers(); + const hub = new NotificationHub({ presenceTypingTtlMs: 50 }); + const firstSocket = createMockHubSocket(); + const secondSocket = createMockHubSocket(); + registerSocketActor(firstSocket, sawyer); + registerSocketActor(secondSocket, { ...sawyer, clientId: "browser-2" }); + hub.subscribe(firstSocket, { + kind: "thread-detail", + threadId: "thread-1", + }); + hub.subscribe(secondSocket, { + kind: "thread-detail", + threadId: "thread-1", + }); + + hub.setTyping(firstSocket, "thread-1", true); + await vi.advanceTimersByTimeAsync(25); + hub.setTyping(secondSocket, "thread-1", true); + await vi.advanceTimersByTimeAsync(25); + expect(hub.getPresenceSnapshot().threads["thread-1"]?.[0]?.typing).toBe( + true, + ); + + await vi.advanceTimersByTimeAsync(25); + expect(hub.getPresenceSnapshot().threads["thread-1"]?.[0]?.typing).toBe( + false, + ); + hub.unregisterClient(firstSocket); + hub.unregisterClient(secondSocket); + releaseSocketActor(firstSocket); + releaseSocketActor(secondSocket); + }); + it("folds typing protocol messages into presence and removes presence before releasing the actor", () => { const hub = new NotificationHub(); const deps = protocolDeps(hub); diff --git a/apps/server/test/public/public-thread-interactions.test.ts b/apps/server/test/public/public-thread-interactions.test.ts index aab83752da..16a468d407 100644 --- a/apps/server/test/public/public-thread-interactions.test.ts +++ b/apps/server/test/public/public-thread-interactions.test.ts @@ -371,6 +371,12 @@ describe("public thread interaction routes", () => { method: "POST", headers: { "content-type": "application/json", + [CLAIMED_IDENTITY_HEADER]: encodeClaimedIdentityHeader({ + clientId: "browser-bob", + displayName: "Bob", + handle: "bob", + imageUrl: null, + }), }, body: JSON.stringify(createAllowOnceResolution()), }, @@ -381,6 +387,10 @@ describe("public thread interaction routes", () => { status: "resolving", resolution: createAllowOnceResolution(), }); + expect( + getPendingInteraction(harness.db, registered.interaction.id) + ?.resolvedByHandle, + ).toBe("alice"); const conflictingResolveResponse = await harness.app.request( `/api/v1/threads/${thread.id}/interactions/${registered.interaction.id}/resolve`, @@ -420,6 +430,118 @@ describe("public thread interaction routes", () => { }); }); + it("attributes plugin responses and cancellations to the first responder", async () => { + await withTestHarness(async (harness) => { + const { thread } = seedThreadFixture(harness, { + session: { id: "host-public-plugin-interaction-attribution" }, + }); + const firstResult = + harness.deps.pendingInteractions.requestPluginInteraction({ + pluginId: "secrets", + threadId: thread.id, + rendererId: "secret-request", + title: "Add secrets", + payload: { fields: [{ name: "API_KEY" }] }, + timeoutMs: 10_000, + }); + const [firstInteraction] = + harness.deps.pendingInteractions.listPendingThreadInteractions( + thread.id, + ); + if (!firstInteraction) { + throw new Error("Expected a pending plugin interaction"); + } + + const respondResponse = await harness.app.request( + `/api/v1/threads/${thread.id}/interactions/${firstInteraction.id}/respond`, + { + method: "POST", + headers: { + "content-type": "application/json", + [CLAIMED_IDENTITY_HEADER]: encodeClaimedIdentityHeader({ + clientId: "browser-alice", + displayName: "Alice", + handle: "alice", + imageUrl: null, + }), + }, + body: JSON.stringify({ value: { accepted: true } }), + }, + ); + expect(respondResponse.status).toBe(200); + await expect(firstResult).resolves.toEqual({ + outcome: "submitted", + value: { accepted: true }, + }); + expect( + getPendingInteraction(harness.db, firstInteraction.id) + ?.resolvedByHandle, + ).toBe("alice"); + + const duplicateResponse = await harness.app.request( + `/api/v1/threads/${thread.id}/interactions/${firstInteraction.id}/respond`, + { + method: "POST", + headers: { + "content-type": "application/json", + [CLAIMED_IDENTITY_HEADER]: encodeClaimedIdentityHeader({ + clientId: "browser-bob", + displayName: "Bob", + handle: "bob", + imageUrl: null, + }), + }, + body: JSON.stringify({ value: { accepted: false } }), + }, + ); + expect(duplicateResponse.status).toBe(409); + expect( + getPendingInteraction(harness.db, firstInteraction.id) + ?.resolvedByHandle, + ).toBe("alice"); + + const cancelledResult = + harness.deps.pendingInteractions.requestPluginInteraction({ + pluginId: "secrets", + threadId: thread.id, + rendererId: "secret-request", + title: "Add another secret", + payload: { fields: [{ name: "SECOND_KEY" }] }, + timeoutMs: 10_000, + }); + const [cancelledInteraction] = + harness.deps.pendingInteractions.listPendingThreadInteractions( + thread.id, + ); + if (!cancelledInteraction) { + throw new Error("Expected a pending plugin interaction to cancel"); + } + const cancelResponse = await harness.app.request( + `/api/v1/threads/${thread.id}/interactions/${cancelledInteraction.id}/cancel`, + { + method: "POST", + headers: { + [CLAIMED_IDENTITY_HEADER]: encodeClaimedIdentityHeader({ + clientId: "browser-bob", + displayName: "Bob", + handle: "bob", + imageUrl: null, + }), + }, + }, + ); + expect(cancelResponse.status).toBe(200); + await expect(cancelledResult).resolves.toEqual({ + outcome: "cancelled", + reason: "user", + }); + expect( + getPendingInteraction(harness.db, cancelledInteraction.id) + ?.resolvedByHandle, + ).toBe("bob"); + }); + }); + it("rejects unavailable command decisions and malformed provider-specific resolutions", async () => { await withTestHarness(async (harness) => { const { thread } = seedThreadFixture(harness, { diff --git a/apps/server/test/services/threads/thread-speaker.test.ts b/apps/server/test/services/threads/thread-speaker.test.ts index df1bd3c710..b9f3866da2 100644 --- a/apps/server/test/services/threads/thread-speaker.test.ts +++ b/apps/server/test/services/threads/thread-speaker.test.ts @@ -2,6 +2,7 @@ import { appendStoredThreadEvent, upsertCollaborator } from "@bb/db"; import { threadScope } from "@bb/domain"; import { describe, expect, it } from "vitest"; import { prepareTurnSubmitCommandPayload } from "../../../src/services/threads/thread-commands.js"; +import { appendClientTurnEvent } from "../../../src/services/threads/thread-events.js"; import { textInput } from "../../helpers/prompt-input.js"; import { seedEnvironment, @@ -20,7 +21,7 @@ const execution = { } as const; describe("thread turn speakers", () => { - it("adds a speaker only once a different human has acted in the thread", async () => { + it("adds a speaker only once a different human has authored a message", async () => { await withTestHarness(async (harness) => { const { host } = seedHostSession(harness.deps); const { project } = seedProjectWithSource(harness.deps, { @@ -45,15 +46,57 @@ describe("thread turn speakers", () => { { displayName: "Bob", handle: "bob", imageUrl: null }, 1, ); - appendStoredThreadEvent(harness.db, harness.hub, { + appendClientTurnEvent(harness.deps, { + actorHandle: null, + environmentId: environment.id, + execution, + initiator: "user", + input: textInput("legacy message"), + requestMethod: "turn/start", + senderThreadId: null, + source: "tell", + target: { kind: "new-turn" }, + threadId: thread.id, + type: "client/turn/requested", + }); + + const nullOnlyHistory = await prepareTurnSubmitCommandPayload( + harness.deps, + { + actorHandle: "alice", + environment, + execution, + input: textInput("first attributed message"), + permissionEscalation: "deny", + providerThreadId: "provider-thread-speaker", + target: { mode: "start" }, + thread, + }, + ); + expect(nullOnlyHistory).not.toHaveProperty("speaker"); + + appendClientTurnEvent(harness.deps, { actorHandle: "alice", + environmentId: environment.id, + execution, + initiator: "user", + input: textInput("alice message"), + requestMethod: "turn/start", + senderThreadId: null, + source: "tell", + target: { kind: "new-turn" }, + threadId: thread.id, + type: "client/turn/requested", + }); + appendStoredThreadEvent(harness.db, harness.hub, { + actorHandle: "bob", data: { reason: "manual-stop" }, scope: threadScope(), threadId: thread.id, type: "system/thread/interrupted", }); - const singleHuman = await prepareTurnSubmitCommandPayload(harness.deps, { + const singleAuthor = await prepareTurnSubmitCommandPayload(harness.deps, { actorHandle: "alice", environment, execution, @@ -63,7 +106,7 @@ describe("thread turn speakers", () => { target: { mode: "start" }, thread, }); - expect(singleHuman).not.toHaveProperty("speaker"); + expect(singleAuthor).not.toHaveProperty("speaker"); const multiplayer = await prepareTurnSubmitCommandPayload(harness.deps, { actorHandle: "bob", diff --git a/packages/db/src/data/events.ts b/packages/db/src/data/events.ts index eebf7b1a05..66ac9e7340 100644 --- a/packages/db/src/data/events.ts +++ b/packages/db/src/data/events.ts @@ -634,6 +634,7 @@ export function countDistinctThreadEventActors( .where( and( eq(events.threadId, args.threadId), + eq(events.type, "client/turn/requested"), isNotNull(events.actorHandle), args.excludedHandle === undefined ? undefined diff --git a/packages/db/src/data/index.ts b/packages/db/src/data/index.ts index b1390c0272..2587dd5017 100644 --- a/packages/db/src/data/index.ts +++ b/packages/db/src/data/index.ts @@ -452,7 +452,6 @@ export { setPendingInteractionInterrupted, setPendingInteractionResolving, setPendingInteractionResolved, - setPendingInteractionResolvedByHandle, } from "./pending-interactions.js"; export type { CreatePendingInteractionInput, diff --git a/packages/db/src/data/pending-interactions.ts b/packages/db/src/data/pending-interactions.ts index 01d3597998..79dfe44bb5 100644 --- a/packages/db/src/data/pending-interactions.ts +++ b/packages/db/src/data/pending-interactions.ts @@ -1,4 +1,4 @@ -import { and, desc, eq, inArray, isNull } from "drizzle-orm"; +import { and, desc, eq, inArray } from "drizzle-orm"; import type { SQL } from "drizzle-orm"; import type { PendingInteractionStatus } from "@bb/domain"; import type { DbConnection, DbTransaction } from "../connection.js"; @@ -47,6 +47,7 @@ export interface SetPendingInteractionTerminalStateArgs { allowedCurrentStatuses?: readonly PendingInteractionStatus[]; id: string; resolution: string | null; + resolvedByHandle?: string; resolvedAt?: number; status: "interrupted" | "resolved"; statusReason: string | null; @@ -55,6 +56,7 @@ export interface SetPendingInteractionTerminalStateArgs { export interface SetPendingInteractionResolvingArgs { id: string; resolution: string; + resolvedByHandle?: string; } export interface InterruptPendingInteractionsForThreadsArgs { @@ -119,6 +121,9 @@ function updatePendingInteractionTerminalState( resolution: args.resolution, statusReason: args.statusReason, resolvedAt: args.resolvedAt ?? now, + ...(args.resolvedByHandle === undefined + ? {} + : { resolvedByHandle: args.resolvedByHandle }), updatedAt: now, }) .where( @@ -274,39 +279,21 @@ export function setPendingInteractionResolved( args: { id: string; resolution: string; + resolvedByHandle?: string; }, ): PendingInteractionRow | null { return updatePendingInteractionTerminalState(db, { id: args.id, allowedCurrentStatuses: ["pending", "resolving"], resolution: args.resolution, + ...(args.resolvedByHandle === undefined + ? {} + : { resolvedByHandle: args.resolvedByHandle }), status: "resolved", statusReason: null, }); } -export function setPendingInteractionResolvedByHandle( - db: PendingInteractionWriteConnection, - args: { - id: string; - resolvedByHandle: string; - }, -): PendingInteractionRow | null { - return ( - db - .update(pendingInteractions) - .set({ resolvedByHandle: args.resolvedByHandle }) - .where( - and( - eq(pendingInteractions.id, args.id), - isNull(pendingInteractions.resolvedByHandle), - ), - ) - .returning() - .get() ?? null - ); -} - export function setPendingInteractionResolving( db: PendingInteractionWriteConnection, args: SetPendingInteractionResolvingArgs, @@ -320,6 +307,9 @@ export function setPendingInteractionResolving( status: "resolving", resolution: args.resolution, statusReason: null, + ...(args.resolvedByHandle === undefined + ? {} + : { resolvedByHandle: args.resolvedByHandle }), updatedAt: now, }) .where( @@ -337,6 +327,7 @@ export function setPendingInteractionInterrupted( db: PendingInteractionWriteConnection, args: { id: string; + resolvedByHandle?: string; statusReason: string; }, ): PendingInteractionRow | null { @@ -344,6 +335,9 @@ export function setPendingInteractionInterrupted( id: args.id, allowedCurrentStatuses: ["pending", "resolving"], resolution: null, + ...(args.resolvedByHandle === undefined + ? {} + : { resolvedByHandle: args.resolvedByHandle }), status: "interrupted", statusReason: args.statusReason, }); diff --git a/packages/db/test/data/events.test.ts b/packages/db/test/data/events.test.ts index aae9212e26..818f41acf6 100644 --- a/packages/db/test/data/events.test.ts +++ b/packages/db/test/data/events.test.ts @@ -201,49 +201,63 @@ describe("events", () => { expect(all).toHaveLength(2); }); - it("stores event actors and counts distinct human speakers", () => { + it("counts distinct attributed human message authors only", () => { const { db, thread } = setup(); insertEvents(db, noopNotifier, [ { - actorHandle: "alice", threadId: thread.id, sequence: 1, - type: "system/error", + type: "client/turn/requested", ...threadEventFields, - data: JSON.stringify({ message: "first" }), + data: clientTurnRequestData("request-null", "legacy message"), }, { - actorHandle: "bob", + actorHandle: "alice", threadId: thread.id, sequence: 2, - type: "system/error", + type: "client/turn/requested", ...threadEventFields, - data: JSON.stringify({ message: "second" }), + data: clientTurnRequestData("request-alice", "alice message"), }, { + actorHandle: "bob", threadId: thread.id, sequence: 3, - type: "system/error", + type: "system/thread/interrupted", ...threadEventFields, - data: JSON.stringify({ message: "system" }), + data: JSON.stringify({ reason: "manual-stop" }), }, ]); expect(listEvents(db, { threadId: thread.id })).toMatchObject([ + { actorHandle: null }, { actorHandle: "alice" }, { actorHandle: "bob" }, - { actorHandle: null }, ]); expect( countDistinctThreadEventActors(db, { threadId: thread.id }), - ).toBe(2); + ).toBe(1); expect( countDistinctThreadEventActors(db, { excludedHandle: "alice", threadId: thread.id, }), - ).toBe(1); + ).toBe(0); + + insertEvents(db, noopNotifier, [ + { + actorHandle: "bob", + threadId: thread.id, + sequence: 4, + type: "client/turn/requested", + ...threadEventFields, + data: clientTurnRequestData("request-bob", "bob message"), + }, + ]); + expect( + countDistinctThreadEventActors(db, { threadId: thread.id }), + ).toBe(2); }); it("stores derived item columns when provided", () => { diff --git a/packages/db/test/data/pending-interactions.test.ts b/packages/db/test/data/pending-interactions.test.ts index 205a2d7fea..05cd4840dc 100644 --- a/packages/db/test/data/pending-interactions.test.ts +++ b/packages/db/test/data/pending-interactions.test.ts @@ -13,7 +13,6 @@ import { interruptPendingInteractionsForThreads, listPendingInteractionsByThread, setPendingInteractionResolved, - setPendingInteractionResolvedByHandle, } from "../../src/data/pending-interactions.js"; import { createThread } from "../../src/data/threads.js"; @@ -164,21 +163,21 @@ describe("pending interactions", () => { decision: "allow_for_session", grantedPermissions: null, }), + resolvedByHandle: "alice", }); expect(resolved).toMatchObject({ id: older.id, + resolvedByHandle: "alice", status: "resolved", }); expect( - setPendingInteractionResolvedByHandle(db, { - id: older.id, - resolvedByHandle: "alice", - }), - ).toMatchObject({ resolvedByHandle: "alice" }); - expect( - setPendingInteractionResolvedByHandle(db, { + setPendingInteractionResolved(db, { id: older.id, + resolution: JSON.stringify({ + decision: "allow_for_session", + grantedPermissions: null, + }), resolvedByHandle: "bob", }), ).toBeNull(); From ac9c59f94a6acd2d1f2ef9e683b2859dc5139ddd Mon Sep 17 00:00:00 2001 From: Sawyer Hood Date: Sat, 18 Jul 2026 10:48:19 -0700 Subject: [PATCH 7/8] Order presence snapshots so a stale response cannot roll back a newer one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit beginSnapshot now issues a monotonically increasing snapshot id and applySnapshot drops any response that is no longer the most recently begun request, so overlapping (re)connect snapshots — e.g. during rapid reconnects or an identity rebind — can never overwrite the state a newer snapshot seeded. Per-thread realtime guards are unchanged. Co-Authored-By: Claude Fable 5 --- apps/app/src/lib/presence-store.test.ts | 21 ++++++++++++++++ apps/app/src/lib/presence-store.ts | 32 ++++++++++++++++++++----- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/apps/app/src/lib/presence-store.test.ts b/apps/app/src/lib/presence-store.test.ts index fdff19e03a..69c13ade6d 100644 --- a/apps/app/src/lib/presence-store.test.ts +++ b/apps/app/src/lib/presence-store.test.ts @@ -110,6 +110,27 @@ describe("PresenceStore", () => { expect(store.getSummaryHandles("thr_1")).toEqual(["carol"]); }); + it("drops an older snapshot that resolves after a newer one applied", () => { + const store = new PresenceStore(); + const captureA = store.beginSnapshot(); + const captureB = store.beginSnapshot(); + + // B (the newer request) resolves first and seeds newer state, including + // the removal of thr_gone; then A's stale response arrives. + store.applySnapshot({ thr_1: [viewer("newer")] }, captureB); + store.applySnapshot( + { thr_1: [viewer("older")], thr_gone: [viewer("ghost")] }, + captureA, + ); + + expect(store.getThreadViewers("thr_1").map((v) => v.handle)).toEqual([ + "newer", + ]); + expect(store.getThreadViewers("thr_gone")).toEqual([]); + expect(store.getSummaryHandles("thr_1")).toEqual(["newer"]); + expect(store.getSummaryHandles("thr_gone")).toEqual([]); + }); + it("returns a stable reference for an unchanged roster", () => { const store = new PresenceStore(); store.setThreadViewers("thr_1", [viewer("alice")]); diff --git a/apps/app/src/lib/presence-store.ts b/apps/app/src/lib/presence-store.ts index d4c0d41b31..9afd067260 100644 --- a/apps/app/src/lib/presence-store.ts +++ b/apps/app/src/lib/presence-store.ts @@ -19,6 +19,12 @@ import { wsManager, type WebSocketManager } from "./ws"; const EMPTY_VIEWERS: readonly PresenceViewer[] = []; const EMPTY_HANDLES: readonly string[] = []; +/** Handle returned by beginSnapshot; identifies one snapshot request. */ +export interface SnapshotCapture { + snapshotId: number; + sinceGeneration: number; +} + export class PresenceStore { private viewersByThreadId = new Map(); private summaryHandlesByThreadId = new Map(); @@ -31,6 +37,10 @@ export class PresenceStore { private generation = 0; private viewerTouchGeneration = new Map(); private summaryTouchGeneration = new Map(); + // Snapshot requests are ordered too: only the most recently begun snapshot + // may apply, so a slow response from an earlier (re)connect can never roll + // back the state a later snapshot already seeded. + private latestSnapshotId = 0; attach(manager: WebSocketManager): () => void { const unsubscribePresence = manager.onThreadPresence((message) => { @@ -50,7 +60,7 @@ export class PresenceStore { } private async seedFromSnapshot(): Promise { - const sinceGeneration = this.beginSnapshot(); + const capture = this.beginSnapshot(); let snapshot: PresenceSnapshotResponse; try { snapshot = await request( @@ -60,23 +70,33 @@ export class PresenceStore { // Presence is cosmetic; a failed seed just waits for live broadcasts. return; } - this.applySnapshot(snapshot.threads, sinceGeneration); + this.applySnapshot(snapshot.threads, capture); } /** Capture before requesting a snapshot; pass the result to applySnapshot. */ - beginSnapshot(): number { - return this.generation; + beginSnapshot(): SnapshotCapture { + this.latestSnapshotId += 1; + return { + snapshotId: this.latestSnapshotId, + sinceGeneration: this.generation, + }; } /** * Apply the HTTP snapshot (complete current rosters): flush entries absent * from it and replace the rest — except threads a realtime message touched - * after `sinceGeneration`, whose newer live state (including removal) wins. + * after the capture, whose newer live state (including removal) wins. A + * snapshot that is no longer the most recently begun one is dropped whole: + * a newer request supersedes it regardless of response arrival order. */ applySnapshot( threads: Record, - sinceGeneration: number, + capture: SnapshotCapture, ): void { + if (capture.snapshotId !== this.latestSnapshotId) { + return; + } + const sinceGeneration = capture.sinceGeneration; const untouched = (touches: Map, threadId: string) => (touches.get(threadId) ?? 0) <= sinceGeneration; for (const threadId of [...this.viewersByThreadId.keys()]) { From 9da6ce7ddd5bd49d16e0d362058d7d805275f3f4 Mon Sep 17 00:00:00 2001 From: Sawyer Hood Date: Sat, 18 Jul 2026 15:21:24 -0700 Subject: [PATCH 8/8] Add multiplayer implementation workflows --- .bb/workflows/multiplayer-wave-1.js | 167 +++++++++++++++++++ .bb/workflows/multiplayer-wave-2.js | 180 +++++++++++++++++++++ .bb/workflows/multiplayer-wave-3.js | 188 ++++++++++++++++++++++ .bb/workflows/multiplayer-wave-4-fixes.js | 172 ++++++++++++++++++++ 4 files changed, 707 insertions(+) create mode 100644 .bb/workflows/multiplayer-wave-1.js create mode 100644 .bb/workflows/multiplayer-wave-2.js create mode 100644 .bb/workflows/multiplayer-wave-3.js create mode 100644 .bb/workflows/multiplayer-wave-4-fixes.js diff --git a/.bb/workflows/multiplayer-wave-1.js b/.bb/workflows/multiplayer-wave-1.js new file mode 100644 index 0000000000..898e9fb94f --- /dev/null +++ b/.bb/workflows/multiplayer-wave-1.js @@ -0,0 +1,167 @@ +export const meta = { + name: "multiplayer-wave-1", + description: + "Wave 1: connect gate membership (WS1) and local server claimed-identity plumbing (WS2) in parallel", + phases: [ + { + title: "Implement", + detail: "WS1 connect cloud and WS2 server identity, disjoint ownership", + }, + ], +}; + +const shared = ` +You are one of two parallel workers implementing "multiplayer bb" wave 1 in a +SHARED working tree on branch bb/multiplayer (wave 0 is commit 26722ea2d, +already in your workspace). Another worker is editing a disjoint set of files +concurrently — touch ONLY the files listed under YOUR OWNERSHIP, and scope all +validation commands with turbo --filter so you never run the other package's +suite. + +Design invariants (decided, do not relitigate): +- Identity is CLAIMED-ONLY. Clients self-assert identity via the + x-bb-claimed-identity header (see @bb/domain claimed-identity module). + Admission gateways never assert identity into product data. +- The bb server never AUTHORIZES by identity, only attributes. Admission is + enforced entirely at the connect gate (or network boundary). +- Membership is admission-only and owner-managed. The connect audit log is the + system's only verified access record. +- Follow AGENTS.md at the repo root (parse at boundaries, no accepted-but- + ignored fields, no unnecessary optionality, no db mocking in tests). + +Rules: no new dependencies; no git commits or git add (leave all changes in +the working tree); pipe slow command output to /tmp files and read the file. +Your final message is a machine-consumed report: outcome, files changed (paths), +key API surfaces, checks run with actual results, blockers/assumptions. +`; + +const ws1Prompt = `${shared} +YOUR OWNERSHIP: apps/connect/** only. Do NOT modify packages/connect-db (its +server_member schema + migration 0006 already landed), apps/server, +packages/db, packages/domain. + +Objective: make the connect gate admit invited members and give owners a +member-management API. + +Wave 0 already provides in packages/connect-db/src/schema.ts: serverMember +(server_id, user_id, added_by_user_id, created_at; PK (server_id,user_id); +index server_member_user_id_idx) exported in the schema map, plus the existing +auditLog table. + +Tasks: +1. Gate admission — apps/connect/src/worker.ts (the owner check around lines + 405-445 that returns 403 "not your server"): when the session user is not + the server owner, admit them if a server_member row exists for (serverId, + sessionUserId). The desktop-credential path stays owner-only. Inspect + apps/connect/src/session.ts / cache.ts for how label->server resolution and + caching work and keep the membership check consistent with those patterns + (a per-request D1 query is acceptable if that matches existing style). +2. Admission audit — on member admission, append an audit_log row (action + "member-admitted", userId = member, detail JSON with serverId and + subdomain). Debounce so steady-state traffic does not write a row per + request: an in-memory per-isolate map with a ~15-minute window is fine; + at-least-once duplicates across isolate restarts are acceptable. This log + is the system's ONLY verified access record, so make sure the write path + actually lands. +3. Member management API — following the existing worker API conventions (see + how apps/connect/src/servers.ts routes are registered in worker.ts), add + owner-session-authenticated endpoints: + - GET /api/servers/:serverId/members -> array of { userId, handle, name, + image, addedByUserId, createdAt } + - POST /api/servers/:serverId/members with { handle } -> resolve + profile.handle to a user (match existing handle normalization), insert + server_member with addedByUserId = owner; 404 unknown handle, 409 already + a member, 400 if the handle is the owner's own. + - DELETE /api/servers/:serverId/members/:userId -> remove; 404 if absent. + All three return 403 unless the session user owns the server. Add/remove + write audit rows ("member-added" / "member-removed"). +4. Tests — colocated *.test.ts next to the code (follow worker.test.ts / + servers.test.ts harness style): member session admitted through the gate, + non-member still 403, owner-only member CRUD (each authz failure), unknown + handle 404, duplicate 409, owner-handle 400, audit rows written. + +Validation: pnpm exec turbo run typecheck --filter=@bb/connect and +pnpm exec turbo run test --filter=@bb/connect (pipe to /tmp, read results). +`; + +const ws2Prompt = `${shared} +YOUR OWNERSHIP: apps/server/** (except apps/server/src/ws/hub.ts — see below) +plus a NEW file packages/db/src/data/collaborators.ts and its export wiring +and tests. Do NOT modify: packages/db/src/schema.ts, packages/db/src/migrate.ts, +packages/domain/**, apps/connect/**. + +Objective: plumb claimed identity through the local server — every API request +and websocket connection resolves to an actor, collaborators are recorded, and +sockets expose their actor for the upcoming presence work. + +Wave 0 already provides: +- @bb/domain claimed-identity module: CLAIMED_IDENTITY_HEADER + ("x-bb-claimed-identity"), ClaimedIdentity { handle, displayName, + imageUrl: string|null, clientId }, decodeClaimedIdentityHeader(value) -> + identity-with-normalized-handle or null, normalizeHandle, + encodeClaimedIdentityHeader. +- @bb/db collaborators table: handle (PK), display_name, image_url, + first_seen_at, last_seen_at. +- The ws client protocol already tolerates a "typing" message as a no-op. + +Tasks: +1. packages/db/src/data/collaborators.ts (new; follow the style of existing + modules in packages/db/src/data/): upsertCollaborator(db, { handle, + displayName, imageUrl }, now) inserting (firstSeenAt = lastSeenAt = now) or + updating display fields + lastSeenAt; getCollaborator(db, handle); + listCollaborators(db). Wire exports the same way sibling data modules are + exported. +2. Request actor resolution in apps/server: a small typed module (place it + where server services conventionally live) that resolves an actor from + request headers via decodeClaimedIdentityHeader, falling back to a default + local-operator identity built once at startup: handle = + normalizeHandle(os.userInfo().username) (fallback "local"), displayName = + the OS username or hostname, imageUrl null, clientId "local". Wire it into + the /api/v1 request path following how apps/server/src/server.ts currently + mounts public routes and passes deps/context into handlers — minimal, + typed, no "as" casts. Attribution consumers land in a later wave; this wave + only needs the actor resolvable per-request and the collaborator recorded. +3. Collaborator recording: upsert via the new data module whenever a request + or ws connection resolves an actor, with an in-memory debounce keyed by + handle (skip the write when displayName/imageUrl are unchanged and the last + write was under 60 seconds ago). +4. Socket actors: resolve the actor from the upgrade request at the GET /ws + accept site in apps/server/src/server.ts and record the socket->actor + association in a new module apps/server/src/ws/socket-actors.ts (register + on open, release on close — the close path runs through + onClientSocketClose in apps/server/src/ws/client-protocol.ts; wire + minimally). Expose getSocketActor(socket). Do NOT modify hub.ts — presence + lands later and will consume getSocketActor. +5. Tests: packages/db test for upsert semantics using in-memory sqlite + (createConnection(":memory:") + migrate(db); never mock the db). apps/server + tests via the existing harness patterns: header -> actor (valid, malformed + -> local default), normalization collision ("Sawyer " and "sawyer" are one + collaborator), debounce skip, socket-actors register/release (unit-test the + module directly if the harness lacks ws coverage). + +Validation: pnpm exec turbo run typecheck --filter=@bb/server --filter=@bb/db +then pnpm exec turbo run test --filter=@bb/db and --filter=@bb/server, piped +to /tmp files (the server suite is slow — read the file, do not stream). Two +KNOWN-FLAKY server tests unrelated to you: the install-machine-script 404 +fallback test and the public-host-management revoke-machine timeout — if they +fail, rerun that file in isolation before treating it as your regression. +`; + +phase("Implement"); +const results = await parallel([ + () => + agent(ws1Prompt, { + label: "WS1 connect gate + members", + provider: "codex", + model: "gpt-5.6-sol", + reasoningLevel: "high", + }), + () => + agent(ws2Prompt, { + label: "WS2 server claimed identity", + provider: "codex", + model: "gpt-5.6-sol", + reasoningLevel: "high", + }), +]); +return { ws1: results[0], ws2: results[1] }; diff --git a/.bb/workflows/multiplayer-wave-2.js b/.bb/workflows/multiplayer-wave-2.js new file mode 100644 index 0000000000..eaf80d7166 --- /dev/null +++ b/.bb/workflows/multiplayer-wave-2.js @@ -0,0 +1,180 @@ +export const meta = { + name: "multiplayer-wave-2", + description: + "Wave 2: attribution + agent-visible speakers (WS3) and hub-derived presence (WS4) in parallel", + phases: [ + { + title: "Implement", + detail: "WS3 attribution and WS4 presence, disjoint ownership", + }, + ], +}; + +const shared = ` +You are one of two parallel workers implementing "multiplayer bb" wave 2 in a +SHARED working tree on branch bb/multiplayer. Waves 0-1 are committed +(26722ea2d, 9571629e3) and already in your workspace. Another worker is +editing a disjoint set of files concurrently — touch ONLY files under YOUR +OWNERSHIP and scope validation with turbo --filter. + +Landed foundation you build on: +- @bb/domain claimed-identity: ClaimedIdentity { handle, displayName, + imageUrl: string|null, clientId }; identity is claimed-only and the server + never authorizes by it, only attributes. +- @bb/domain change-kinds: typingMessageSchema (inbound client ws message), + presenceViewerSchema, threadPresenceMessageSchema, + presenceSummaryMessageSchema (+ lenient counterparts). +- @bb/db: collaborators table + data module; nullable attribution columns + events.actor_handle, threads.created_by_handle, + queued_thread_messages.actor_handle, pending_interactions.resolved_by_handle + (all plain text, NULL = not human-initiated / pre-multiplayer). +- apps/server: every /api/v1 request resolves an actor — use + getRequestActor(context) from apps/server/src/services/actors.ts. Every + client ws socket has an actor — getSocketActor(socket) from + apps/server/src/ws/socket-actors.ts. + +Rules: follow AGENTS.md at the repo root; no new dependencies; no git commits +or git add; pipe slow command output to /tmp files and read the file. Two +KNOWN-FLAKY server tests unrelated to this work: the install-machine-script +404-fallback test and the public-host-management revoke-machine timeout — if +one fails, rerun that file in isolation before treating it as your regression. +Your final message is a machine-consumed report: outcome, files changed, +key API surfaces/behavior, checks run with actual results, blockers. +`; + +const ws3Prompt = `${shared} +YOUR OWNERSHIP: apps/server/src/routes/threads/**, apps/server/src/services/ +threads/**, packages/db/src/data/** (events/threads/queued-thread-messages/ +pending-interactions modules), packages/host-daemon-contract/**, +apps/host-daemon/**, and their tests. Do NOT modify: apps/server/src/server.ts, +apps/server/src/ws/**, packages/server-contract/** (the other worker owns +those this wave), packages/db/src/schema.ts, packages/db/src/migrate.ts, +packages/domain/**, apps/connect/**. + +Objective: attribution end to end — every human-initiated action records its +actor, and the agent can see who is speaking in multi-human threads. + +Tasks: +1. Message sends: POST /threads/:id/send (apps/server/src/routes/threads/ + actions.ts, the send handler) resolves the actor via getRequestActor and + threads it through sendThreadMessage (apps/server/src/services/threads/ + thread-send.ts) so the client/turn/requested events row is written with + actor_handle (insert path: appendAndQueueSendThreadMessageInTransaction -> + packages/db/src/data/events.ts insertEvents). Queued sends carry + actor_handle on queued_thread_messages and preserve it when the queue is + drained into a real send. Messages sent by other threads or plugins (the + trigger/senderThreadId paths) stay NULL — actor attribution applies to the + human request path only. IMPORTANT CONTRACT RULE: the actor comes ONLY from + getRequestActor, never from any request-body field. +2. Thread create: POST /threads (routes/threads/base.ts -> + services/threads/thread-create.ts) writes threads.created_by_handle for + human-origin creates; agent/plugin origins stay NULL. +3. Stop/interrupt: POST /threads/:id/stop records the acting handle on the + stop it produces — attach it to the lifecycle/system event data the stop + path already emits (inspect requestThreadStopForCurrentState and the run + lifecycle events; add the actor to the event payload, do not invent a new + event type). +4. Approvals: POST /threads/:id/interactions/:interactionId/resolve + (routes/threads/interactions.ts -> pendingInteractions service) records + pending_interactions.resolved_by_handle for the resolving request. +5. Agent-visible speakers: extend the turn command payload built in + thread-send.ts (prepareReadyThreadTurnCommand / + prepareTurnSubmitCommandPayload) with an OPTIONAL speaker + { handle, displayName } field in packages/host-daemon-contract, populated + ONLY when the thread has 2 or more distinct human actors recorded (count + distinct non-null events.actor_handle for the thread — add a targeted query + to the events data module, no full-table scans in JS). In apps/host-daemon, + render the speaker as a short annotation prefixed to the user message text + handed to the provider session (e.g. "[from @handle] " — inspect how the + daemon builds provider input from the turn payload and match its idioms). + Single-human threads must produce byte-identical provider input to today. +6. Because the turn payload crosses the server<->daemon wire, bump + HOST_DAEMON_PROTOCOL_VERSION in packages/host-daemon-contract/src/ + commands.ts from 58 to 59 (repo rule: any wire-visible change bumps it). +7. Tests (in-memory sqlite via createConnection(":memory:") + migrate(db), + never mock the db): send writes actor_handle; queued send preserves it + through the drain; thread create records created_by_handle for human + origin and NULL for plugin origin; resolve records resolved_by_handle; + speaker present only at >=2 distinct human actors; daemon-side annotation + rendering if the daemon has unit-testable prompt assembly. + +Validation: pnpm exec turbo run typecheck --filter=@bb/server +--filter=@bb/db --filter=@bb/host-daemon-contract --filter=@bb/host-daemon, +then turbo test for the same filters, piped to /tmp files. +`; + +const ws4Prompt = `${shared} +YOUR OWNERSHIP: apps/server/src/ws/** (including hub.ts and client-protocol.ts), +apps/server/src/server.ts (minimal wiring only), a new presence service module +under apps/server/src/services/, new presence route files under +apps/server/src/routes/, packages/server-contract/** (presence route contract), +and their tests. Do NOT modify: apps/server/src/routes/threads/**, +apps/server/src/services/threads/**, packages/db/**, packages/domain/**, +packages/host-daemon-contract/**, apps/host-daemon/**, apps/connect/**. + +Objective: hub-derived presence — who is viewing which thread, with typing, +broadcast live and snapshot-queryable. + +Design (decided): a client socket with a claimed actor that is subscribed to +thread-detail: is "viewing" that thread. Presence is DERIVED from +the hub's existing subscription bookkeeping — no heartbeats, nothing +persisted. Viewers are deduped by handle across sockets/devices. + +Tasks: +1. Presence tracking: build a presence service that observes subscribe/ + unsubscribe/socket-close for thread-detail targets (hook the hub's + subscribe/unsubscribe/unregisterClient paths; get actors via + getSocketActor). Maintain per-thread viewer sets keyed by handle with + per-handle socket refcounts so closing one of two tabs does not drop + presence. +2. Typing: implement the currently-no-op "typing" case in apps/server/src/ws/ + client-protocol.ts — mark the sending socket's actor as typing in that + thread with a ~6 second TTL (timer-based expiry; expiry emits a presence + update). Only meaningful when that actor is a current viewer. +3. Broadcasts: on any viewer-set or typing change for a thread, send + threadPresenceMessageSchema-shaped messages ({ type: "thread-presence", + threadId, viewers: [{handle, displayName, imageUrl, typing}] }) to that + thread's thread-detail subscribers, and presenceSummaryMessageSchema-shaped + ({ type: "presence-summary", threads: { [threadId]: handles[] } }) to + thread-list subscribers (summary may carry only changed threads' entries — + document the merge semantics you choose; an empty array removes a thread's + entry). Validate outgoing messages with the strict schemas at the send + boundary, matching how changed-messages are produced today. Suppress + no-op rebroadcasts (unchanged viewer set and typing state). +4. Snapshot: GET /api/v1/presence returning current viewers per thread + ({ threads: { [threadId]: viewers[] } }). Add the route to + packages/server-contract following existing public-api conventions and + implement it in apps/server/src/routes/ (register it wherever public routes + are registered). Follow the repo rule: no accepted-but-ignored fields. +5. Self-visibility: include the requesting/viewing actor in viewer sets (the + UI can filter itself out client-side later); do not special-case the local + operator. +6. Tests via the existing server test harness: subscribe -> viewer appears; + dedupe across two sockets with the same handle; unsubscribe/close -> + removed only when the last socket goes; typing TTL expiry; broadcast + payloads validate against the strict schemas; snapshot route returns the + derived state; no-op suppression. + +Validation: pnpm exec turbo run typecheck --filter=@bb/server +--filter=@bb/server-contract, then turbo test for @bb/server and +@bb/server-contract if it has tests, piped to /tmp files. +`; + +phase("Implement"); +const results = await parallel([ + () => + agent(ws3Prompt, { + label: "WS3 attribution + speakers", + provider: "codex", + model: "gpt-5.6-sol", + reasoningLevel: "high", + }), + () => + agent(ws4Prompt, { + label: "WS4 hub presence + typing", + provider: "codex", + model: "gpt-5.6-sol", + reasoningLevel: "high", + }), +]); +return { ws3: results[0], ws4: results[1] }; diff --git a/.bb/workflows/multiplayer-wave-3.js b/.bb/workflows/multiplayer-wave-3.js new file mode 100644 index 0000000000..6ae03cd9fc --- /dev/null +++ b/.bb/workflows/multiplayer-wave-3.js @@ -0,0 +1,188 @@ +export const meta = { + name: "multiplayer-wave-3", + description: + "Wave 3: multiplayer UI (WS5, Fable) and CLI/SDK/membership surfaces (WS6, Sol) in parallel", + phases: [ + { + title: "Implement", + detail: "WS5 app UI and WS6 CLI/SDK/tunnel surfaces, disjoint ownership", + }, + ], +}; + +const shared = ` +You are one of two parallel workers implementing "multiplayer bb" wave 3 in a +SHARED working tree on branch bb/multiplayer (waves 0-2.5 committed through +5cfbcb190, already in your workspace). Another worker is editing a disjoint +set of files concurrently — touch ONLY files under YOUR OWNERSHIP and scope +validation with turbo --filter. + +Landed foundation: +- Identity is CLAIMED-ONLY: clients self-assert via the x-bb-claimed-identity + header (@bb/domain claimed-identity module: ClaimedIdentity { handle, + displayName, imageUrl: string|null, clientId }, encodeClaimedIdentityHeader, + decodeClaimedIdentityHeader, normalizeHandle, CLAIMED_IDENTITY_HEADER). + /ws also accepts the same encoded value via the "identity" query parameter. + Absent identity = local-operator default server-side. The server NEVER + authorizes by identity, only attributes. +- Presence: server broadcasts strict-schema "thread-presence" ({ threadId, + viewers: [{handle, displayName, imageUrl, typing}] }) to thread-detail + subscribers and partial "presence-summary" ({ threads: { [threadId]: + handles[] }, empty array removes an entry }) to thread-list subscribers; + lenient parse schemas exported from @bb/domain change-kinds. Snapshot at + GET /api/v1/presence (contract in packages/server-contract/src/api/ + presence.ts). Typing: ws client message { type: "typing", threadId, + typing } with a 6s server TTL. +- Attribution read model: TimelineUserConversationRow.actorHandle + (string|null) is populated end to end; events.actor_handle etc. recorded + server-side for sends/creates/stops/approvals. +- Connect cloud: server_member table + owner-session member management API on + the worker (GET/POST /api/servers/:serverId/members, DELETE .../members/ + :userId), gate admits members, admission audit rows. + +Rules: follow AGENTS.md at the repo root; no new dependencies; no git commits +or git add; pipe slow command output to /tmp files and read the file. Two +KNOWN-FLAKY server tests: install-machine-script 404-fallback and +public-host-management revoke-machine timeout — rerun in isolation before +treating either as your regression. Your final message is a machine-consumed +report: outcome, files changed, key surfaces/behavior, checks run with actual +results, blockers. +`; + +const ws5Prompt = `${shared} +YOUR OWNERSHIP: apps/app/** only. Do NOT touch apps/server, apps/cli, +apps/connect, packages/** (all read-model plumbing you need already exists). + +Objective: the visible multiplayer layer — claimed-identity picker, presence +avatars, typing, follow-mode, and message authorship in the bb app. + +Tasks: +1. Identity store: a small module in apps/app owning the claimed identity — + localStorage-persisted { handle, displayName, imageUrl: null, clientId } + (clientId: generated once and persisted). The DESKTOP/localhost context + sends NO identity (the server's local-operator default covers it); when the + app runs remotely (not the desktop shell, not a localhost origin), prompt + for a display name on first load with a lightweight dialog (name -> handle + via normalizeHandle) and provide a settings surface to edit it later. + Follow existing app conventions for settings sections and dialogs. +2. Wire identity outbound: attach x-bb-claimed-identity (via + encodeClaimedIdentityHeader) to the app's API request layer when an + identity exists, and append ?identity= to the /ws URL + (including reconnects). Find the single fetch/ws construction points and + wire there — no scattered per-call headers. +3. Presence state: parse inbound "thread-presence" and "presence-summary" ws + messages with the LENIENT schemas from @bb/domain in the app's existing ws + message dispatch, keep per-thread viewer rosters and the sidebar summary in + the app's state layer (follow existing patterns for ws-fed state), and seed + from GET /api/v1/presence when the socket (re)connects. +4. Render presence: + - Thread header (apps/app/src/views/thread-detail/ThreadDetailHeader.tsx): + avatar row of current viewers excluding yourself (own handle), imageUrl + or initials, display name in tooltip. + - Typing indicator near the composer (ThreadDetailPromptArea / + FollowUpPromptBox area): "@alice is typing" for other viewers' typing. + - Sidebar (apps/app/src/components/sidebar/ThreadRow.tsx): compact viewer + avatars/dots on threads from the summary; clicking one navigates to that + thread (follow/jump). +5. Typing emit: send { type: "typing", threadId, typing: true } over the ws + while the composer is focused with non-empty draft (throttled well under + the 6s TTL), and typing: false on blur/empty/send. +6. Message authorship: GeneratedConversationMessage (and the timeline row + path) renders an author chip/avatar for user rows using + TimelineUserConversationRow.actorHandle — shown only when the loaded + timeline contains 2+ distinct non-null actorHandles, so single-author + threads stay exactly as today. Also set the optimistic user row's + actorHandle to your own claimed handle (currently hardcoded null in + apps/app/src/hooks/cache-owners/thread-runtime-cache-owner.ts + buildOptimisticUserMessageRow) when an identity exists. +7. Theme discipline: all new colors derived from --canvas/--ink via + color-mix per apps/app/src/components/ui/theme.css conventions (no + oklch/achromatic literals — theme.test.ts guards this); sanctioned + typography tokens only. Add Storybook stories for the presence avatar + row and typing indicator following neighboring story patterns. +8. Validation: pnpm exec turbo run typecheck --filter=@bb/app and + pnpm exec turbo run test --filter=@bb/app piped to /tmp files. +`; + +const ws6Prompt = `${shared} +YOUR OWNERSHIP: apps/cli/**, packages/sdk/**, packages/tunnel-client/**, +apps/connect/**, apps/server/src/routes/** (NEW members proxy files + their +registration only), packages/server-contract/** (members contract), docs/**, +and tests for all of those. Do NOT touch apps/app/** (the other worker owns +it), apps/server/src/services/** except where a members proxy service +naturally must live, packages/db/**, packages/domain/**. + +Objective: membership management surfaces (CLI/SDK) end to end, plus the +transport marker that keeps member management owner-console-only. + +Design invariants (decided): membership is owner-only. Remote members reach +the local server exclusively through the connect tunnel, so a tunnel-origin +marker is the transport check that keeps the local members surface away from +them. The connect worker is the authority on the member list. + +Tasks: +1. Tunnel origin marker: in packages/tunnel-client (see src/headers.ts + headersForLoopbackRequest and src/session.ts where loopback HTTP requests + and ws upgrades are re-issued), STRIP any inbound "x-bb-via-tunnel" header + from forwarded traffic and SET "x-bb-via-tunnel: 1" on every re-issued + request/upgrade. Remote clients therefore can never reach the local server + without the marker; local processes never carry it. +2. Connect worker credential auth: extend ONLY the member-management endpoints + in apps/connect (src/members.ts) to also accept the server's own tunnel + credential as owner-equivalent: Authorization: Bearer verified + against server.credential_hash for the SAME :serverId (inspect how the + tunnel path verifies that credential today and reuse that verification). + Session-cookie auth keeps working unchanged. +3. Local members proxy: add GET/POST/DELETE /api/v1/members to the local + server (contract in packages/server-contract following existing public-api + conventions; implementation as a new route file registered like siblings). + It proxies to the connect worker's member API using the server's stored + connect credential and connect base URL — INSPECT how the server-side + connect integration stores the tunnel credential and worker origin (likely + the connect plugin / tunnel client setup) and place the proxy where that + credential legitimately lives; if it can only live inside the connect + plugin, implement it there and report the placement. Behavior: reject any + request carrying x-bb-via-tunnel with 403 (member management is + owner-console-only); 404-style clear error when the server is not enrolled + in connect; pass through the worker's 403/404/409 semantics. +4. SDK (packages/sdk): a members area (list/add/remove) against + /api/v1/members, a presence getter for GET /api/v1/presence, and a client + option to set the claimed-identity header (via @bb/domain + encodeClaimedIdentityHeader) so agents/CLI can attribute themselves. +5. CLI (apps/cli): bb members list / bb members add / bb members + remove using the SDK, with clear errors for not-enrolled, unknown + handle, duplicate member, and tunnel-origin rejection. Follow existing + command structure/output conventions. +6. Docs: per docs/cli-guide-and-skill.md, update every discoverable surface + for the new command + the claimed-identity/presence concepts (bb guide + chapter, CLI help, skill surfaces as that doc directs). Do NOT implement + any open-mode/LAN bind flag in this wave; do not document it as existing. +7. Tests: tunnel-client header marker (strip + set); connect worker + credential-auth on member endpoints (valid credential, wrong credential, + wrong server); local proxy authz (tunnel-marked request rejected, + not-enrolled error) with the existing server test harness patterns; SDK + area unit tests per sibling areas; CLI output tests per existing command + tests. +8. Validation: pnpm exec turbo run typecheck and test with --filter for each + touched package (@bb/cli, @bb/sdk, @bb/tunnel-client, @bb/connect, + @bb/server, @bb/server-contract), piped to /tmp files. +`; + +phase("Implement"); +const results = await parallel([ + () => + agent(ws5Prompt, { + label: "WS5 multiplayer UI", + provider: "claude-code", + model: "claude-fable-5", + reasoningLevel: "medium", + }), + () => + agent(ws6Prompt, { + label: "WS6 members CLI/SDK/tunnel", + provider: "codex", + model: "gpt-5.6-sol", + reasoningLevel: "high", + }), +]); +return { ws5: results[0], ws6: results[1] }; diff --git a/.bb/workflows/multiplayer-wave-4-fixes.js b/.bb/workflows/multiplayer-wave-4-fixes.js new file mode 100644 index 0000000000..8dc50ffc97 --- /dev/null +++ b/.bb/workflows/multiplayer-wave-4-fixes.js @@ -0,0 +1,172 @@ +export const meta = { + name: "multiplayer-wave-4-fixes", + description: + "Wave 4: fix the 7 gpt-5.6 review findings across connect, server/db, and app", + phases: [ + { + title: "Fix", + detail: "Three parallel fixers with disjoint ownership", + }, + ], +}; + +const shared = ` +You are one of three parallel workers fixing review findings for "multiplayer +bb" in a SHARED working tree on branch bb/multiplayer (waves 0-3 committed +through 59cc824cb). Touch ONLY files under YOUR OWNERSHIP; scope validation +with turbo --filter. Follow AGENTS.md at the repo root. No new dependencies; +no git commits or git add; pipe slow output to /tmp files and read the file. +Known-flaky server tests (NOT yours): install-machine-script 404-fallback, +public-host-management revoke timeout — rerun in isolation before treating a +failure as your regression. Final message = machine-consumed report: outcome, +files changed, how each assigned finding was fixed, checks run with results, +blockers. + +Design invariants (do not relitigate): identity is claimed-only and the local +server never authorizes by identity; member management is owner-only AND +owner-console-only; the connect worker audit log is the system's only +verified record; single-human threads must produce byte-identical provider +input. +`; + +const connectPrompt = `${shared} +YOUR OWNERSHIP: apps/connect/** only. + +FINDING 1 (High) — a pre-marker (v58) tunnel bypasses owner-console-only +member management: the local /api/v1/members route rejects requests carrying +x-bb-via-tunnel, but tunnels opened by an old tunnel-client never stamp the +marker, so remote members could reach the route. Fix it at the boundary WE +control regardless of installed tunnel-client version: in the connect worker +(apps/connect/src/worker.ts), BLOCK any forwarded visitor request whose path +targets the local member-management surface (/api/v1/members and subpaths) +with a 403 JSON error BEFORE it is sent through the TunnelDO — for every +visitor session, owner included (member management is owner-console-only by +design; the owner uses the CLI/desktop on the machine). Apply the same block +on the websocket-upgrade path only if that path can carry such URLs. Keep the +existing local marker check as defense in depth (do not touch it — it is +outside your ownership). Add worker tests: forwarded GET/POST/DELETE +/api/v1/members* as owner session and as member session both get 403 and are +never forwarded; unrelated /api/v1/* paths still forward. + +FINDING 2 (High) — membership mutations can commit without their audit rows: +in apps/connect/src/members.ts, addServerMember inserts server_member then +appends the member-added audit row as a second statement, and +removeServerMember deletes then audits; a failed audit write leaves an +unaudited authorization change. Make each mutation atomic with its audit row +— drizzle's D1/SQLite batch API (db.batch([...])) executes statements in one +implicit transaction on D1; the in-memory sqlite test double must behave +equivalently (verify how the existing tests construct the db and keep both +paths atomic — if batch is unavailable on the test double, use the +transaction primitive that works on both and document it). Preserve existing +status-code semantics (409 duplicate via unique-constraint detection must +still work). Add tests that force the audit insert to fail (e.g. drop or +rename the audit_log table in the test db, or inject a failing db) and assert +membership is unchanged for both add and remove. + +Validation: pnpm exec turbo run typecheck --filter=@bb/connect and +pnpm exec turbo run test --filter=@bb/connect, piped to /tmp. +`; + +const serverPrompt = `${shared} +YOUR OWNERSHIP: apps/server/src/services/** , apps/server/src/routes/threads/ +interactions.ts, apps/server/src/ws/**, packages/db/src/data/**, and their +tests. Do NOT touch apps/connect/**, apps/app/**, packages/tunnel-client/**, +apps/server/src/routes/members.ts. + +FINDING 3 (High) — speaker gating counts non-message actors as authors: +countDistinctThreadEventActors (packages/db/src/data/events.ts, ~line 624) +counts every actor-bearing event, so a manual stop by Bob makes Alice's next +message get "[from @alice]" even though she is the only author — violating +the 2+ distinct MESSAGE authors gate and byte-identical single-human input. +Restrict the count to attributed human message events (type +'client/turn/requested' with actor_handle NOT NULL); keep it a targeted SQL +count. Verify the index situation for the new predicate (existing +events_thread_type_* indexes likely cover it; add an index ONLY if the query +plan requires it, per AGENTS.md). Update/extend tests: NULL-only history -> +no speaker; one message author + a manual stop by someone else -> no speaker; +two message authors -> speaker present. + +FINDING 5 (Medium) — interaction attribution gaps: the /resolve route writes +resolved_by_handle as a second write after the state transition ( +apps/server/src/routes/threads/interactions.ts ~line 59), and the plugin +/respond route (~line 76) never records attribution at all. Pass the +request-scoped actor into the pendingInteractions service so the state +transition and the first resolver's handle persist in the SAME write for BOTH +provider /resolve and plugin /respond paths (and /cancel if it resolves +state). First resolver wins under racing duplicates. Tests: provider resolve, +plugin respond, and a duplicate/racing second responder that must not +overwrite the first handle (in-memory sqlite, never mock the db). + +FINDING 6 (Medium) — typing state is per-handle, not per-socket: in +apps/server/src/services/presence.ts, ViewerState holds one typing boolean + +one timeout for a handle, so one tab sending typing:false (or its TTL +expiring) clears typing for the same person's other active device. Track +typing TTL per socket and derive handle-level typing as "any socket active"; +clear a socket's typing state when that socket unsubscribes/closes. Add a +two-socket same-handle test: socket A stops typing (explicit false AND +separately TTL expiry) while socket B is still typing -> handle stays typing; +both stop -> cleared. + +Validation: pnpm exec turbo run typecheck --filter=@bb/server --filter=@bb/db +then turbo test for both, piped to /tmp. +`; + +const appPrompt = `${shared} +YOUR OWNERSHIP: apps/app/** only. + +FINDING 4 (Medium) — claimed-identity changes do not rebind the live +websocket: the socket's actor is fixed at upgrade time, and the app connects +before the first-load name prompt completes, so presence/typing stay +attributed to the default actor until some unrelated reconnect, while HTTP +requests immediately use the new identity. Fix: when the claimed identity is +saved, edited, or cleared (apps/app/src/lib/claimed-identity-store.ts / +ClaimIdentityDialog / IdentitySettingsSection), trigger a controlled +reconnect of the ws manager (apps/app/src/lib/ws.ts already re-evaluates the +URL provider and re-subscribes on reconnect — use its existing reconnect +machinery; do not build a second socket). Ensure resubscription and presence +reseeding still happen (they are wired to the reconnect path). Tests: saving +identity triggers exactly one reconnect with the new ?identity= URL; +edit and clear also rebind; jsdom-level is fine following the existing +ws/presence test patterns. + +FINDING 7 (Medium) — the reconnect presence snapshot can overwrite newer +realtime state: apps/app/src/lib/presence-store.ts fires an async GET +/api/v1/presence on (re)connect and unconditionally replaces all state when +it resolves, so a thread-presence/presence-summary broadcast that arrived +while the request was in flight is clobbered by the older snapshot with +nothing to repair it. Guard with a generation/ordering scheme: bump a +generation on every applied realtime message; when the snapshot resolves, +apply it only for state not touched by a newer generation (or re-request / +merge — pick the simplest correct scheme and document it in a comment). +Tests: deferred snapshot response with an intervening realtime update AND an +intervening realtime removal — both must survive the snapshot's arrival. + +Validation: pnpm exec turbo run typecheck --filter=@bb/app and +pnpm exec turbo run test --filter=@bb/app, piped to /tmp. +`; + +phase("Fix"); +const results = await parallel([ + () => + agent(connectPrompt, { + label: "fix: connect gate + audit atomicity", + provider: "codex", + model: "gpt-5.6-sol", + reasoningLevel: "high", + }), + () => + agent(serverPrompt, { + label: "fix: speaker gate + interactions + typing", + provider: "codex", + model: "gpt-5.6-sol", + reasoningLevel: "high", + }), + () => + agent(appPrompt, { + label: "fix: ws rebind + snapshot race", + provider: "claude-code", + model: "claude-fable-5", + reasoningLevel: "medium", + }), +]); +return { connect: results[0], server: results[1], app: results[2] };