ai-browser-bridge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/main.ts","../src/features/terminal/createCliFactory.ts","../src/features/terminal/internal/cliRunner.ts","../src/features/providers/chatgpt/chatgptPage.ts","../src/config/providersConfig.ts","../src/config/defaultsConfig.ts","../src/config/runtimeConfig.ts","../src/features/providers/conversationUrl.ts","../src/features/providers/guestSessionError.ts","../src/features/providers/chatgpt/chatgptWorkspace.ts","../src/features/providers/chrome/internal/browserManager.ts","../src/features/store/internal/sessionStore.ts","../src/features/domain/errors.ts","../src/features/domain/models/modelUrls.ts","../src/features/domain/models/anthropicProfiles.ts","../src/features/domain/models/googleProfiles.ts","../src/features/domain/models/openaiGpt5Profiles.ts","../src/features/domain/models/openaiProfiles.ts","../src/features/domain/models/zaiProfiles.ts","../src/features/domain/models/modelProfiles.ts","../src/features/domain/models/modelLookup.ts","../src/features/domain/permissions.ts","../src/features/domain/domainSchemas.ts","../src/features/tools/internal/mcpServer.ts","../src/features/user-config/internal/userConfig.ts","../src/features/user-config/userConfigSchemas.ts","../src/features/tools/createMcpServerFactory.ts","../src/features/tools/toolsSchemas.ts","../src/features/store/storeSchemas.ts","../src/features/providers/chatgptProviderConfig.ts","../src/features/providers/claude/claudeConnector.ts","../src/features/providers/gemini/geminiPage.ts","../src/features/providers/geminiProviderConfig.ts","../src/features/providers/genericWebChatPage.ts","../src/features/providers/unknownProviderError.ts","../src/features/providers/providerRegistry.ts","../src/features/providers/providersSchemas.ts","../src/features/agentGateway/askGatewayServer.ts","../src/features/agentGateway/serveAskGateway.ts","../src/features/agentGateway/agentGatewaySchemas.ts","../src/features/bridge/internal/bridgeEngine.ts","../src/features/tunnel/internal/cloudflareTunnel.ts","../src/features/tunnel/internal/tunnelSchemas.ts","../src/features/tunnel/internal/cloudflareTunnelClass.ts","../src/features/bridge/loadConfig.ts","../src/features/bridge/internal/orchestrator.ts","../src/features/bridge/createEngineFactory.ts","../src/features/bridge/fanoutOrchestrator.ts","../src/features/bridge/bridgeSchemas.ts","../src/features/terminal/providerLabel.ts","../src/features/terminal/tui/App.tsx","../src/features/terminal/tui/ComposerAssistPanel.tsx","../src/features/terminal/tui/ComposerAssistSections.tsx","../src/features/terminal/tui/composerConstants.ts","../src/features/terminal/tui/visibleMenuItems.ts","../src/features/terminal/tui/ComposerInputBar.tsx","../src/features/terminal/tui/MessagePane.tsx","../src/features/terminal/tui/roleThemeConfig.ts","../src/features/terminal/tui/StatusBar.tsx","../src/features/terminal/tui/statusBarHelpers.ts","../src/features/terminal/tui/useComposerCommands.ts","../src/features/terminal/tui/projectAwarePrompt.ts","../src/features/terminal/tui/useComposerInput.ts","../src/features/terminal/tui/useComposerKeyboard.ts","../src/features/terminal/tui/input-suggestions/commandRules.ts","../src/features/terminal/tui/fileAutocompleteHelpers.ts","../src/features/terminal/tui/fileAutocompleteComplete.ts","../src/features/terminal/tui/fileAutocompleteTypes.ts","../src/features/terminal/tui/input-suggestions/types.ts","../src/features/terminal/tui/input-suggestions/filterSuggestions.ts","../src/features/terminal/tui/input-suggestions/parseSlashInput.ts","../src/features/terminal/tui/input-suggestions/repoPathSuggestions.ts","../src/features/terminal/tui/input-suggestions/pathSuggestionUtils.ts","../src/features/terminal/tui/input-suggestions/pathSuggestions.ts","../src/features/terminal/tui/input-suggestions/sessionCheckpointSuggestions.ts","../src/features/terminal/tui/input-suggestions/commandArgHandlers.ts","../src/features/terminal/tui/input-suggestions/commandArgumentSuggestions.ts","../src/features/terminal/tui/input-suggestions/commandNameSuggestions.ts","../src/features/terminal/tui/input-suggestions/loadSuggestions.ts","../src/features/terminal/tui/useComposerKeyboardCommand.ts","../src/features/terminal/tui/composerHistory.ts","../src/features/terminal/tui/useComposerKeyboardTyping.ts","../src/features/terminal/tui/useComposerSend.ts","../src/features/terminal/tui/useComposerState.ts","../src/features/terminal/tui/useComposerStdin.ts","../src/features/terminal/tui/useComposerStop.ts","../src/features/terminal/tui/shortcuts.ts","../src/features/terminal/tui/useComposerSuggestions.ts","../src/features/terminal/tui/useComposer.ts","../src/features/terminal/subcommandOpts.ts","../src/features/terminal/registerCli.ts","../src/features/terminal/terminalSchemas.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { NodeRuntime } from \"@effect/platform-node\";\nimport { Effect } from \"effect\";\nimport { runCli } from \"./features/terminal/index.ts\";\n\n/**\n * Application entrypoint.\n *\n * Wraps the CLI in NodeRuntime.runMain for proper signal handling (SIGINT/SIGTERM),\n * fiber interruption, and graceful shutdown. The CLI itself still uses Commander\n * internally — the full @effect/cli migration is a future pass.\n */\nconst program = Effect.tryPromise({\n try: () => runCli(process.argv),\n catch: (err) => err,\n});\n\nNodeRuntime.runMain(program);\n","import { Command } from \"commander\";\nimport { CliRunner } from \"./internal/cliRunner.ts\";\nimport { registerCliCommands } from \"./registerCli.ts\";\n\n/** Register and run the bridge CLI (TUI + headless subcommands). */\nexport async function runCli(argv: string[]): Promise<void> {\n const runner = new CliRunner();\n const program = new Command();\n registerCliCommands(program, runner);\n await program.parseAsync(argv);\n}\n","import { execFile } from \"node:child_process\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, extname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { type AskGatewayDeps, serveAskGatewayStdio } from \"@/features/agentGateway\";\nimport { startEngine } from \"@/features/bridge\";\nimport type { BridgeEngine } from \"@/features/bridge\";\nimport { type FanoutResult, fanoutAsk, fanoutFailed } from \"@/features/bridge\";\nimport { findModelProfile, listModelProfiles } from \"@/features/domain\";\nimport { PERMISSION_MODES, normalizePermissionMode } from \"@/features/domain\";\nimport type {\n Attachment,\n CommandContext,\n CommandDef,\n ConnectorSetupResult,\n Message,\n} from \"@/features/domain\";\nimport { downloadAll, extractAllMessages, loadManifest } from \"@/features/providers\";\nimport { createProject, listProjects, listTasks, moveChatToProject } from \"@/features/providers\";\nimport { BRIDGE_DEBUG_PORT, BrowserManager } from \"@/features/providers\";\nimport { conversationUrlFromIdOrUrl, isSameChatGptConversation } from \"@/features/providers\";\nimport {\n type BridgeProviderId,\n getBrowserProvider,\n normalizeProvider,\n parseProviderList,\n} from \"@/features/providers\";\nimport { listCheckpoints, restoreCheckpoint } from \"@/features/store\";\nimport { bridgeLogPath } from \"@/features/store\";\nimport { exportsDir, screenshotsDir, sessionsDir } from \"@/features/store\";\nimport {\n type SessionExport,\n type SessionStoreOptions,\n exportSession,\n getLatestSession,\n listSessions,\n loadSession,\n} from \"@/features/store\";\nimport type { SessionMetadata } from \"@/features/store\";\nimport { ensureInsideRepo, toolRegistry, trimOutput } from \"@/features/tools\";\nimport {\n loadCustomCommands,\n loadProjectInstructions,\n renderCustomCommandPrompt,\n} from \"@/features/user-config\";\nimport { render } from \"ink\";\nimport type { Page } from \"playwright\";\nimport React from \"react\";\nimport type {\n AskOptions,\n ChatCmdOptions,\n CommonCliOptions,\n DownloadCmdOptions,\n DownloadResult,\n LoginOptions,\n ProjectCmdOptions,\n ServeOptions,\n TaskCmdOptions,\n} from \"../cliTypes.ts\";\nimport { getProviderDisplayName } from \"../providerLabel.ts\";\nimport { BridgeApp } from \"../tui/App.tsx\";\n\n// --- commands/commands.config.ts ---\n/** Slash-command metadata without handler functions. */\ninterface CommandMeta {\n /** Primary command name (without `/`). */\n name: string;\n /** One-line description for `/help`. */\n description: string;\n /** Optional alternate names that resolve to this command. */\n aliases?: string[];\n}\n\n/** Session, transcript, and checkpoint command metadata. */\nconst SESSION_COMMANDS: CommandMeta[] = [\n { name: \"conversations\", description: \"List and open ChatGPT conversations\" },\n {\n name: \"resume\",\n aliases: [\"open\"],\n description: \"Resume a browser conversation or local session\",\n },\n { name: \"sessions\", description: \"List local bridge sessions\" },\n { name: \"transcript\", description: \"Print local session transcript\" },\n { name: \"copy\", description: \"Copy local session transcript to clipboard\" },\n { name: \"export\", description: \"Export local session transcript\" },\n { name: \"checkpoints\", description: \"List file checkpoints\" },\n { name: \"restore\", description: \"Restore files from a checkpoint\" },\n {\n name: \"rewind\",\n aliases: [\"retry\"],\n description: \"Edit the last prompt, or restore checkpoint files\",\n },\n];\n\n/** Model and context-window command metadata. */\nconst MODEL_COMMANDS: CommandMeta[] = [\n { name: \"model\", description: \"Show or switch the ChatGPT model\" },\n { name: \"context\", description: \"Show context window usage\" },\n];\n\n/** MCP connector, permissions, and project-task command metadata. */\nconst MCP_COMMANDS: CommandMeta[] = [\n {\n name: \"task\",\n aliases: [\"work\"],\n description: \"Send a project-agent task with MCP tool instructions\",\n },\n { name: \"permissions\", description: \"Show or switch MCP permission mode\" },\n { name: \"mcp\", description: \"Show MCP connector setup and exposed tools\" },\n { name: \"connector\", description: \"Open ChatGPT MCP connector setup\" },\n { name: \"review\", description: \"Ask ChatGPT to review local changes\" },\n];\n\n/** Browser orchestration and terminal UI command metadata. */\nconst BROWSER_COMMANDS: CommandMeta[] = [\n { name: \"help\", description: \"List all available commands\" },\n { name: \"new\", description: \"Start a new ChatGPT conversation\" },\n { name: \"stop\", description: \"Stop the active ChatGPT response\" },\n { name: \"compact\", description: \"Ask ChatGPT for a concise progress summary\" },\n { name: \"commands\", description: \"List project/user custom commands\" },\n { name: \"logs\", description: \"Show the local bridge log file path\" },\n { name: \"status\", description: \"Show bridge status\" },\n { name: \"statusline\", description: \"Show status bar fields\" },\n { name: \"clear\", description: \"Clear the terminal chat view\" },\n { name: \"attach-image\", description: \"Attach a repo image file to ChatGPT\" },\n { name: \"screenshot\", description: \"Capture desktop/mobile screenshots for a URL\" },\n { name: \"ui-qa\", description: \"Capture UI screenshots and ask ChatGPT to review them\" },\n { name: \"diff\", description: \"Show current git diff\" },\n { name: \"exit\", description: \"Shutdown the bridge\" },\n];\n\n// --- commands/prompts.ts ---\n\n/**\n * Prompt templates for the project-agent commands (`/task`, `/work`).\n *\n * These build the instruction block sent to ChatGPT that forces it to drive the\n * repo through the MCP connector tools (grep_code/read_file/apply_patch/…) rather\n * than guessing from memory. Kept separate from the command registry so the large\n * static prompt text lives with the other command data, not the dispatch logic.\n */\n\n/** Build the project-agent wrapper used by `/task` and `/work` (no instruction files). */\nfunction buildProjectTaskPrompt(task: string, ctx: CommandContext): string {\n return buildProjectTaskPromptWithInstructions(task, ctx, \"\");\n}\n\n/**\n * Build the project-agent prompt, optionally appending the repo's instruction\n * files (AGENTS.md / CLAUDE.md) so ChatGPT honours project conventions.\n *\n * The prompt deliberately front-loads a \"prove the connector is active\" step:\n * if ChatGPT answers from `/mnt/data` or asks for a zip/tree, the connector is\n * not wired up and the task should not proceed.\n */\nfunction buildProjectTaskPromptWithInstructions(\n task: string,\n ctx: CommandContext,\n projectInstructions: string,\n): string {\n return [\n \"You are helping me modify this local project through the registered MCP connector.\",\n \"\",\n \"Project context:\",\n `- Repo path: ${ctx.config.repoPath}`,\n \"- The terminal bridge exposes narrow local tools; use them instead of guessing from memory.\",\n \"\",\n \"Available MCP tools:\",\n \"- grep_code: search source code and find relevant files.\",\n \"- read_file: inspect exact file contents before proposing or editing.\",\n \"- apply_patch: make minimal code edits through sandbox-validated patches.\",\n \"- run_tests: run only allowlisted verification commands.\",\n \"- git_diff: review the current local diff before reporting completion.\",\n \"\",\n \"Required workflow:\",\n \"1. First action: call an MCP tool such as grep_code or read_file to prove the connector is active.\",\n \"2. Inspect the repository structure with grep_code/read_file and identify the relevant modules.\",\n \"3. Use grep_code to find the files, commands, tests, selectors, and patterns involved.\",\n \"4. Use read_file on the important files before making claims or edits.\",\n \"5. Briefly explain the structure you found and the files that matter.\",\n \"6. Make the smallest correct change, following existing patterns and avoiding unrelated refactors.\",\n \"7. If behavior changes, add or update focused tests when practical.\",\n \"8. Run the smallest useful verification first, then broader tests/build when relevant.\",\n \"9. Use git_diff to review the final diff.\",\n \"10. Report changed files, verification commands, and remaining risks.\",\n \"\",\n \"Rules:\",\n \"- Do not answer from guessing when the MCP tools can inspect the repo.\",\n \"- Do not ask me to paste tree/find output for this repo; use the MCP connector tools instead.\",\n \"- If you see only a hosted sandbox such as /mnt/data, or you ask for a zip/tree/find output, the connector is not active.\",\n \"- Do not use raw shell access or ask for broad local access.\",\n \"- Do not commit unless I explicitly ask.\",\n \"- If the MCP connector tools are unavailable in this chat, say: MCP connector is not active in this chat.\",\n \"- If a needed operation is not available through the tools, say exactly what is missing.\",\n ...(projectInstructions.trim()\n ? [\"\", \"Project instruction files:\", projectInstructions.trim()]\n : []),\n \"\",\n \"User task:\",\n task.trim(),\n ].join(\"\\n\");\n}\n\n// --- commands/formatters.ts ---\n\n/**\n * Pure string builders for the diagnostic/status commands (`/status`, `/mcp`,\n * `/connector`, `/resume`). Separated from the command registry so the dispatch\n * layer stays small and these display helpers can be unit-tested in isolation.\n * None of them perform I/O — they format already-loaded context into text.\n */\n\n/**\n * Normalise a tunnel URL into the connector endpoint ChatGPT points at.\n *\n * Returns null when no tunnel is configured (the bridge has no public URL),\n * which the callers render as \"none\". Accepts URLs already ending in `/mcp` or\n * `/sse` and otherwise appends `/mcp`.\n */\nfunction mcpConnectorUrl(tunnelUrl?: string): string | null {\n if (!tunnelUrl) return null;\n const normalized = tunnelUrl.replace(/\\/+$/, \"\");\n return normalized.endsWith(\"/mcp\") || normalized.endsWith(\"/sse\")\n ? normalized\n : `${normalized}/mcp`;\n}\n\n/** Format a one-block summary of a resumed/loaded local session. */\nfunction formatSessionSummary(session: SessionMetadata, currentId?: string): string {\n const marker = session.id === currentId ? \"current\" : \"loaded\";\n return [\n `Local session ${marker}: ${session.id}`,\n `Repo: ${session.repoPath}`,\n `Model: ${session.model ?? \"unknown\"}`,\n `Context: ${session.contextLimit.toLocaleString()} tokens`,\n `Updated: ${session.updatedAt}`,\n `Tunnel: ${session.tunnelUrl ?? \"none\"}`,\n ].join(\"\\n\");\n}\n\n/** Format the `/status` / `/statusline` overview of the running bridge. */\nfunction formatBridgeStatus(ctx: CommandContext): string {\n const connector = mcpConnectorUrl(ctx.config.tunnelUrl);\n const provider = normalizeProvider(ctx.config.provider);\n return [\n `Provider: ${provider}`,\n `Repo: ${ctx.config.repoPath}`,\n `Branch: ${ctx.statusline?.branch ?? \"unknown\"}`,\n `Session: ${ctx.session?.getId() ?? \"none\"}`,\n `Model: ${ctx.counter.modelLabel}`,\n `Context: ${ctx.counter.summary}`,\n `Permission: ${ctx.permission?.getMode() ?? ctx.config.permissionMode ?? \"auto\"}`,\n `Tool calls: ${ctx.statusline?.toolCallCount() ?? 0}`,\n `Tunnel: ${ctx.config.tunnelUrl ?? \"none\"}`,\n `Connector: ${connector ?? \"none\"}`,\n ].join(\"\\n\");\n}\n\n/** Format `/mcp` diagnostics, including exposed tools and connector-troubleshooting hints. */\nfunction formatMcpDiagnostics(ctx: CommandContext): string {\n const connector = mcpConnectorUrl(ctx.config.tunnelUrl);\n const toolCallCount = ctx.statusline?.toolCallCount() ?? 0;\n return [\n \"MCP bridge diagnostics:\",\n `Local server: http://localhost:${ctx.config.mcpPort}`,\n `Tunnel: ${ctx.config.tunnelUrl ?? \"none\"}`,\n `Connector: ${connector ?? \"none\"}`,\n `Tools: ${[...toolRegistry.keys()].join(\", \")}`,\n `Tool calls observed this session: ${toolCallCount}`,\n `Status: ${toolCallCount > 0 ? \"MCP tool calls observed in this bridge session.\" : \"No MCP tool calls observed yet; the current ChatGPT chat may not have the connector enabled.\"}`,\n \"\",\n \"If ChatGPT says it cannot access local files:\",\n \"1. Startup automatically syncs the current Connector URL into ChatGPT when browser automation is connected.\",\n \"2. Run /connector only to retry that browser setup flow after a UI drift or account permission issue.\",\n \"3. Ask explicitly: use the ai-browser-bridge connector; do not answer from memory.\",\n \"4. A reply mentioning /mnt/data, upload a zip, or paste tree/find output means ChatGPT is not using this local connector.\",\n ].join(\"\\n\");\n}\n\n/** Format the result of the browser-automated ChatGPT connector setup flow. */\nfunction formatConnectorSetupResult(result: ConnectorSetupResult): string {\n return [\n \"\",\n \"Connector setup result:\",\n `URL: ${result.connectorUrl}`,\n `Submitted: ${result.completed ? \"yes\" : \"no\"}`,\n ...(result.steps.length > 0 ? [\"\", \"Steps:\", ...result.steps.map((step) => `- ${step}`)] : []),\n ...(result.warnings.length > 0\n ? [\"\", \"Needs manual attention:\", ...result.warnings.map((warning) => `- ${warning}`)]\n : []),\n \"\",\n \"Automatic startup handles this on each restart when the browser is connected. Manual fallback: ChatGPT Settings -> Apps -> Advanced settings -> Create app, paste the Connector URL, choose no authentication, then enable it in Developer Mode for this chat.\",\n ].join(\"\\n\");\n}\n\n// --- commands/files.format.ts ---\n\n/** Print a formatted attachment table to stdout. */\nfunction printAttachmentTable(attachments: Attachment[]): void {\n if (attachments.length === 0) {\n console.log(\"No attachments captured in this conversation yet.\");\n return;\n }\n const rows = [\n [\"id\", \"role\", \"kind\", \"filename\", \"message\"],\n ...attachments.map((attachment) => [\n attachment.id,\n attachment.role,\n attachment.kind,\n attachment.filename ?? \"\",\n String(attachment.messageIndex),\n ]),\n ];\n const widths = computeColumnWidths(rows);\n for (const row of rows) {\n console.log(formatTableRow({ row, widths }));\n }\n}\n\n/** Compute max column widths for a table row matrix. */\nfunction computeColumnWidths(rows: string[][]): number[] {\n return (rows[0] ?? []).map((...args: [string, number]) =>\n maxColumnLength({ rows, column: args[1] }),\n );\n}\n\n/** Return the longest cell length in one column. */\nfunction maxColumnLength(input: { rows: string[][]; column: number }): number {\n return Math.max(...input.rows.map((row) => (row[input.column] ?? \"\").length));\n}\n\n/** Format one table row with padded cells. */\nfunction formatTableRow(input: { row: string[]; widths: number[] }): string {\n return input.row\n .map((...args: [string, number]) =>\n padTableCell({ cell: args[0], column: args[1], widths: input.widths }),\n )\n .join(\" \");\n}\n\n/** Pad one table cell to its column width. */\nfunction padTableCell(input: { cell: string; column: number; widths: number[] }): string {\n return input.cell.padEnd(input.widths[input.column] ?? 0);\n}\n\n/** Split slash-command args respecting quotes. */\nfunction splitArgs(input: string): string[] {\n const args: string[] = [];\n let current = \"\";\n let quote: \"'\" | '\"' | null = null;\n for (const char of input.trim()) {\n const next = consumeSplitChar({ char, quote, current, args });\n current = next.current;\n quote = next.quote;\n }\n return finalizeSplitArgs({ current, args });\n}\n\n/** Push trailing token when arg splitting finishes. */\nfunction finalizeSplitArgs(input: { current: string; args: string[] }): string[] {\n if (input.current) input.args.push(input.current);\n return input.args;\n}\n\nfunction consumeSplitChar(input: {\n char: string;\n quote: \"'\" | '\"' | null;\n current: string;\n args: string[];\n}): { current: string; quote: \"'\" | '\"' | null } {\n if ((input.char === \"'\" || input.char === '\"') && input.quote === null) {\n return { current: input.current, quote: input.char };\n }\n if (input.char === input.quote) return { current: input.current, quote: null };\n if (/\\s/.test(input.char) && input.quote === null) {\n if (input.current) input.args.push(input.current);\n return { current: \"\", quote: input.quote };\n }\n return { current: input.current + input.char, quote: input.quote };\n}\n\n// --- commands/files.helpers.ts ---\n\n/** Runtime orchestrator extension exposing the active Playwright page. */\ninterface RuntimeOrchestrator {\n page?: Page | null;\n}\n\n/** Normalized attachment download result. */\n/** Lazy-loaded attachment downloader module. */\ninterface AttachmentDownloaderModule {\n downloadAttachment(\n page: Page,\n conversationId: string,\n id: string,\n opts?: { outDir?: string; repoRoot?: string },\n ): Promise<unknown>;\n downloadAll(\n page: Page,\n conversationId: string,\n opts?: { outDir?: string; repoRoot?: string; ids?: string[] },\n ): Promise<unknown>;\n}\n\n/** Path to the lazy-loaded downloader module. */\nconst DOWNLOADER_MODULE = \"../../providers/chatgpt/chatgptPage.ts\";\nconst RED = \"\\u001b[31m\";\nconst RESET = \"\\u001b[0m\";\n\n/** Return the active Playwright page from command context. */\nfunction currentPage(ctx: CommandContext): Page | null {\n const orchestrator = ctx.orchestrator as CommandContext[\"orchestrator\"] & RuntimeOrchestrator;\n return orchestrator.page ?? null;\n}\n\n/** Extract the ChatGPT conversation id from the active page URL. */\nfunction conversationIdFromPage(page: Page): string {\n const match = /\\/c\\/([^/?#]+)/.exec(page.url());\n return match?.[1] ?? \"current\";\n}\n\n/** Whether a value is a non-null object record. */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\n/** Parse `--out <dir>` from slash-command args. */\nfunction parseOutDir(args: string[]): string | undefined {\n const outIndex = args.indexOf(\"--out\");\n if (outIndex === -1) return undefined;\n return args[outIndex + 1];\n}\n\n/** Print an error message to stderr in red. */\nfunction printError(message: string): void {\n console.error(`${RED}${message}${RESET}`);\n}\n\n// --- commands/files.download.helpers.ts ---\n\ninterface HandleDownloadInput {\n page: Page;\n conversationId: string;\n parts: string[];\n manifestIds: string[];\n repoRoot: string;\n}\n\n/** Download one attachment or all attachments from `/files get`. */\nasync function handleFilesDownload(input: HandleDownloadInput): Promise<void> {\n const outDir = parseOutDir(input.parts.slice(2));\n const downloader = await loadDownloader();\n if (input.parts[1] === \"all\") {\n return printBulkResults(\n await downloader.downloadAll(input.page, input.conversationId, {\n repoRoot: input.repoRoot,\n ...(outDir ? { outDir } : {}),\n }),\n );\n }\n await downloadOneAttachment({ input, downloader, outDir });\n}\n\n/** Download a single attachment by id. */\nasync function downloadOneAttachment(input: {\n input: HandleDownloadInput;\n downloader: AttachmentDownloaderModule;\n outDir: string | undefined;\n}): Promise<void> {\n const id = input.input.parts[1];\n if (!id) return printError(\"Usage: download <attachment-id>\");\n if (!input.input.manifestIds.includes(id)) return printError(`No attachment with id \"${id}\".`);\n const raw = await input.downloader.downloadAttachment(\n input.input.page,\n input.input.conversationId,\n id,\n { repoRoot: input.input.repoRoot, ...(input.outDir ? { outDir: input.outDir } : {}) },\n );\n console.log(normalizeDownloadResult({ value: raw, fallbackId: id }).path);\n}\n\nfunction printBulkResults(raw: unknown): void {\n const results = normalizeDownloadAll(raw);\n const succeeded = results.filter((result) => !result.error).length;\n const failed = results.length - succeeded;\n console.log(\n `Downloaded ${succeeded}/${results.length} attachments${failed > 0 ? ` (${failed} failed)` : \"\"}.`,\n );\n for (const result of results) {\n if (result.error) printError(`${result.id ?? \"unknown\"}: ${result.error}`);\n else console.log(`${result.id ?? \"attachment\"} -> ${result.path} (${result.bytes} bytes)`);\n }\n}\n\nasync function loadDownloader(): Promise<AttachmentDownloaderModule> {\n return (await import(DOWNLOADER_MODULE)) as AttachmentDownloaderModule;\n}\n\nfunction normalizeDownloadAll(value: unknown): DownloadResult[] {\n if (!Array.isArray(value)) return [];\n return value.map((...args: [unknown, number]) =>\n normalizeDownloadResult({ value: args[0], fallbackId: `attachment-${args[1] + 1}` }),\n );\n}\n\nfunction normalizeDownloadResult(input: { value: unknown; fallbackId: string }): DownloadResult {\n if (!isRecord(input.value)) return { id: input.fallbackId, path: String(input.value), bytes: 0 };\n return {\n id: typeof input.value.id === \"string\" ? input.value.id : input.fallbackId,\n path: typeof input.value.path === \"string\" ? input.value.path : \"\",\n bytes: typeof input.value.bytes === \"number\" ? input.value.bytes : 0,\n error: typeof input.value.error === \"string\" ? input.value.error : undefined,\n };\n}\n\n// --- commands/files.ts ---\n\n/** CLI slash command for listing and downloading ChatGPT attachments. */\nconst filesCommand: CommandDef = {\n name: \"files\",\n description: \"List or download ChatGPT conversation attachments\",\n handler: (...args: [string, CommandContext]) =>\n handleFilesCommand({ args: args[0], ctx: args[1] }),\n};\n\n/** Dispatch `/files` list or download subcommands. */\nasync function handleFilesCommand(input: { args: string; ctx: CommandContext }): Promise<void> {\n const context = await loadFilesContext(input);\n const parts = splitArgs(input.args);\n if (parts.length === 0) return printAttachmentTable(context.manifest.attachments);\n await routeFilesDownload({ parts, context });\n}\n\n/** Load manifest and page context for `/files`. */\nasync function loadFilesContext(input: { args: string; ctx: CommandContext }) {\n const page = currentPage(input.ctx);\n const conversationId = page ? conversationIdFromPage(page) : \"current\";\n const manifest = await loadManifest(conversationId);\n return { page, conversationId, manifest, repoRoot: input.ctx.config.repoPath };\n}\n\n/** Route `/files get` download requests or print usage errors. */\nasync function routeFilesDownload(input: {\n parts: string[];\n context: {\n page: Page | null;\n conversationId: string;\n manifest: Awaited<ReturnType<typeof loadManifest>>;\n repoRoot: string;\n };\n}): Promise<void> {\n if (input.parts[0] !== \"get\")\n return console.log(\"Usage: /files [get <id>|get all [--out <dir>]]\");\n if (!input.parts[1]) return console.log(\"Usage: /files get <id> or /files get all [--out <dir>]\");\n if (!input.context.page) return printError(\"Browser not connected. Cannot download attachments.\");\n await handleFilesDownload({\n page: input.context.page,\n conversationId: input.context.conversationId,\n parts: input.parts,\n manifestIds: input.context.manifest.attachments.map((item) => item.id),\n repoRoot: input.context.repoRoot,\n });\n}\n\n// --- commands/handlers/helpers/sessionStore.ts ---\n\n/** Session-store options scoped to a repo's `.bridge/sessions`. */\nfunction sessionStore(repoPath: string): SessionStoreOptions {\n return { baseDir: sessionsDir(repoPath) };\n}\n\n// --- commands/handlers/helpers/try-load-session.ts ---\n\n/** Parameters for loading a session without throwing. */\ninterface TryLoadSessionParams {\n /** Session id to load. */\n sessionId: string;\n /** Session store scoped to the repo. */\n options: SessionStoreOptions;\n}\n\n/** Load a session by id, returning null instead of throwing when it is missing. */\nasync function tryLoadSession(params: TryLoadSessionParams) {\n try {\n return await loadSession(params.sessionId, params.options);\n } catch {\n return null;\n }\n}\n\n// --- commands/handlers/helpers/resolve-session-id.ts ---\n\n/** Inputs for resolving which session a command targets. */\ninterface ResolveSessionIdParams {\n /** Raw command arguments. */\n args: string;\n /** Active command context. */\n ctx: CommandContext;\n}\n\n/** Resolve session id from explicit arg, current session, or latest. */\nasync function resolveSessionId(params: ResolveSessionIdParams): Promise<string | null> {\n const [requested] = splitArgs(params.args);\n if (requested) return requested;\n if (params.ctx.session?.getId()) return params.ctx.session.getId();\n const latest = await getLatestSession(sessionStore(params.ctx.config.repoPath));\n return latest?.metadata.id ?? null;\n}\n\n// --- commands/handlers/helpers/repo-file-path.ts ---\n\n/** Inputs for resolving a user path within the repo. */\ninterface ResolveRepoFilePathParams {\n /** Repository root directory. */\n repoRoot: string;\n /** User-supplied relative or absolute path. */\n input: string;\n}\n\n/** Resolve a user path to a repo-relative path, rejecting escapes outside the repo. */\nfunction resolveRepoFilePath(params: ResolveRepoFilePathParams): string {\n if (isAbsolute(params.input)) {\n const rel = relative(resolve(params.repoRoot), resolve(params.input));\n return ensureInsideRepo(rel || \".\", params.repoRoot);\n }\n return ensureInsideRepo(params.input, params.repoRoot);\n}\n\n/** Throw unless the path has a supported raster image extension. */\nfunction assertImagePath(path: string): void {\n const extension = extname(path).toLowerCase();\n if (![\".png\", \".jpg\", \".jpeg\", \".webp\", \".gif\"].includes(extension)) {\n throw new Error(`Unsupported image type: ${basename(path)}`);\n }\n}\n\n// --- commands/handlers/helpers/copy-clipboard.ts ---\n\n/** Copy text to the macOS clipboard via `pbcopy`. */\nasync function copyTextToClipboard(text: string): Promise<void> {\n await new Promise<void>((...args: [() => void, (reason?: unknown) => void]) => {\n runPbcopy({ text, resolve: args[0], reject: args[1] });\n });\n}\n\n/** Spawn `pbcopy` and stream text to stdin. */\nfunction runPbcopy(input: {\n text: string;\n resolve: () => void;\n reject: (reason?: unknown) => void;\n}): void {\n const child = execFile(\"pbcopy\", (error) => {\n if (error) input.reject(error);\n else input.resolve();\n });\n child.stdin?.end(input.text);\n}\n\n// --- commands/handlers/helpers/capture-screenshots.ts ---\n\n/** Inputs for capturing desktop and mobile URL screenshots. */\ninterface CaptureUrlScreenshotsParams {\n /** HTTP or HTTPS URL to capture. */\n url: string;\n /** Repository root for storing screenshots. */\n repoPath: string;\n}\n\n/** Capture full-page desktop + mobile screenshots of a URL into a timestamped dir. */\nasync function captureUrlScreenshots(params: CaptureUrlScreenshotsParams): Promise<string[]> {\n const parsed = parseCaptureUrl(params.url);\n const dir = await prepareScreenshotDir(params.repoPath);\n return await captureWithPlaywright({ parsed, dir });\n}\n\n/** Validate and normalize a screenshot target URL. */\nfunction parseCaptureUrl(url: string): string {\n const parsed = new URL(url);\n if (![\"http:\", \"https:\"].includes(parsed.protocol)) {\n throw new Error(\"Only http and https URLs are supported.\");\n }\n return parsed.toString();\n}\n\n/** Create a timestamped screenshot output directory. */\nasync function prepareScreenshotDir(repoPath: string): Promise<string> {\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const dir = join(screenshotsDir(repoPath), stamp);\n await mkdir(dir, { recursive: true });\n return dir;\n}\n\n/** Playwright capture inputs. */\ninterface CaptureWithPlaywrightParams {\n /** Normalized URL string. */\n parsed: string;\n /** Output directory for PNG files. */\n dir: string;\n}\n\n/** Launch Playwright and write viewport screenshots. */\nasync function captureWithPlaywright(params: CaptureWithPlaywrightParams): Promise<string[]> {\n const { chromium } = await import(\"playwright\");\n const browser = await chromium.launch({ headless: true });\n const outputs: string[] = [];\n try {\n const viewports = [\n { name: \"desktop\", width: 1440, height: 1000 },\n { name: \"mobile\", width: 390, height: 844 },\n ];\n for (const viewport of viewports) {\n outputs.push(\n await captureViewport({ browser, viewport, parsed: params.parsed, dir: params.dir }),\n );\n }\n } finally {\n await browser.close();\n }\n return outputs;\n}\n\n/** Single viewport capture inputs. */\ninterface CaptureViewportParams {\n /** Playwright browser instance. */\n browser: Awaited<ReturnType<Awaited<typeof import(\"playwright\")>[\"chromium\"][\"launch\"]>>;\n /** Viewport name and dimensions. */\n viewport: { name: string; width: number; height: number };\n /** URL to navigate to. */\n parsed: string;\n /** Output directory. */\n dir: string;\n}\n\n/** Capture one viewport screenshot and return its file path. */\nasync function captureViewport(params: CaptureViewportParams): Promise<string> {\n const page = await params.browser.newPage({\n viewport: { width: params.viewport.width, height: params.viewport.height },\n });\n await page.goto(params.parsed, { waitUntil: \"networkidle\", timeout: 45_000 });\n const file = await writeViewportScreenshot({ page, viewport: params.viewport, dir: params.dir });\n await page.close();\n return file;\n}\n\n/** Write a full-page screenshot for one viewport. */\nasync function writeViewportScreenshot(input: {\n page: Awaited<ReturnType<CaptureViewportParams[\"browser\"][\"newPage\"]>>;\n viewport: CaptureViewportParams[\"viewport\"];\n dir: string;\n}): Promise<string> {\n const file = join(input.dir, `${input.viewport.name}.png`);\n await input.page.screenshot({ path: file, fullPage: true });\n return file;\n}\n\n// --- commands/handlers/helpers/session-export.ts ---\n\n/** Parsed `/export` target session and optional output path. */\ninterface SessionExportSelection {\n /** Resolved session id, or null when none is available. */\n sessionId: string | null;\n /** Optional absolute output file path. */\n outputPath?: string;\n}\n\n/** Inputs for parsing `/export` arguments. */\ninterface ResolveSessionExportParams {\n /** Raw command arguments. */\n args: string;\n /** Active command context. */\n ctx: CommandContext;\n}\n\n/** Parse `/export` args into session id and optional output path. */\nasync function resolveSessionExportArgs(\n params: ResolveSessionExportParams,\n): Promise<SessionExportSelection> {\n const parts = splitArgs(params.args);\n if (parts.length === 0) {\n return { sessionId: await resolveSessionId({ args: \"\", ctx: params.ctx }) };\n }\n return resolveSessionExportFromParts({ parts, ctx: params.ctx });\n}\n\n/** Resolve export target from parsed `/export` tokens. */\nasync function resolveSessionExportFromParts(input: {\n parts: string[];\n ctx: CommandContext;\n}): Promise<SessionExportSelection> {\n const first = input.parts[0] ?? \"\";\n const store = sessionStore(input.ctx.config.repoPath);\n const session = await tryLoadSession({ sessionId: first, options: store });\n if (session) {\n return {\n sessionId: session.metadata.id,\n outputPath: input.parts[1] ? resolve(input.parts[1]) : undefined,\n };\n }\n return {\n sessionId: await resolveSessionId({ args: \"\", ctx: input.ctx }),\n outputPath: resolve(first),\n };\n}\n\n/** Default export location for a session when no output path is given. */\nfunction defaultExportPath(params: { repoPath: string; sessionId: string }): string {\n return join(exportsDir(params.repoPath), `${params.sessionId}.md`);\n}\n\n/** Pick export payload (json/jsonl/markdown) based on file extension. */\nfunction exportContentForPath(params: { path: string; exported: SessionExport }): string {\n const extension = extname(params.path).toLowerCase();\n if (extension === \".json\") return params.exported.json;\n if (extension === \".jsonl\") return params.exported.jsonl;\n return params.exported.transcript;\n}\n\n// --- commands/handlers/browser/general.ts ---\n\n/** Start a new ChatGPT conversation. */\nasync function handleNew(_args: string, ctx: CommandContext): Promise<void> {\n await ctx.orchestrator.newConversation();\n console.log(\"Started new conversation.\");\n}\n\n/** Stop the active ChatGPT response. */\nasync function handleStop(_args: string, ctx: CommandContext): Promise<void> {\n const stopped = await ctx.orchestrator.stopResponse();\n console.log(stopped ? \"Stopped active response.\" : \"No active response to stop.\");\n}\n\n/** Ask ChatGPT for a concise progress summary. */\nasync function handleCompact(_args: string, ctx: CommandContext): Promise<void> {\n await ctx.sendMessage(\n \"Summarize our progress so far in a structured format: what we've done, what's in progress, what's next. Be concise.\",\n );\n console.log(\n \"Compaction summary requested. Start a new conversation to continue with that summary.\",\n );\n}\n\n/** Show the local bridge log file path. */\nasync function handleLogs(_args: string, ctx: CommandContext): Promise<void> {\n console.log(`Bridge logs: ${bridgeLogPath(ctx.config.repoPath)}`);\n}\n\n/** Show bridge status. */\nasync function handleStatus(_args: string, ctx: CommandContext): Promise<void> {\n console.log(formatBridgeStatus(ctx));\n}\n\n/** Show status bar fields. */\nasync function handleStatusline(_args: string, ctx: CommandContext): Promise<void> {\n console.log(formatBridgeStatus(ctx));\n}\n\n/** Clear the terminal chat view. */\nasync function handleClear(_args: string, ctx: CommandContext): Promise<void> {\n ctx.clearMessages?.();\n console.log(\n \"Cleared terminal chat view. Browser conversation, context estimate, and local session logs are unchanged.\",\n );\n}\n\n/** Show current git diff via ChatGPT. */\nasync function handleDiff(_args: string, ctx: CommandContext): Promise<void> {\n await ctx.sendMessage(\"Show me the current git diff for the repository.\");\n}\n\n/** Shutdown the bridge. */\nasync function handleExit(_args: string, ctx: CommandContext): Promise<void> {\n if (ctx.shutdown) {\n await ctx.shutdown();\n return;\n }\n console.log(\"Shutting down...\");\n process.exit(0);\n}\n\n// --- commands/handlers/browser/help.ts ---\n\n/** List all available slash commands. */\nasync function handleHelp(_args: string, ctx: CommandContext): Promise<void> {\n const all = getAllCommands();\n console.log(\"\\nAvailable commands:\\n\");\n for (const cmd of all) {\n console.log(` /${cmd.name.padEnd(16)} ${cmd.description}`);\n }\n await printCustomCommands(ctx);\n console.log(\"\");\n}\n\n/** Print project/user custom commands when present. */\nasync function printCustomCommands(ctx: CommandContext): Promise<void> {\n const custom = await loadCustomCommands({ repoRoot: ctx.config.repoPath });\n if (custom.length === 0) return;\n console.log(\"\\nCustom commands:\\n\");\n for (const cmd of custom) {\n console.log(` /${cmd.name.padEnd(16)} ${cmd.description ?? `${cmd.source} command`}`);\n }\n}\n\n/** List project/user custom commands. */\nasync function handleCommands(_args: string, ctx: CommandContext): Promise<void> {\n const custom = await loadCustomCommands({ repoRoot: ctx.config.repoPath });\n if (custom.length === 0) {\n console.log(\"No custom commands found in .bridge/commands or ~/.ai-browser-bridge/commands.\");\n return;\n }\n console.log(\"\\nCustom commands:\\n\");\n for (const command of custom) {\n console.log(\n ` /${command.name.padEnd(16)} ${command.description ?? `${command.source} command`}`,\n );\n }\n console.log(\"\");\n}\n\n// --- commands/handlers/browser/media.ts ---\n\n/** Attach a repo image file to ChatGPT. */\nasync function handleAttachImage(args: string, ctx: CommandContext): Promise<void> {\n const target = args.trim();\n if (!target) {\n console.log(\"Usage: /attach-image <repo-relative-image-path>\");\n return;\n }\n await attachRepoImage({ target, ctx });\n}\n\n/** Resolve, validate, and attach one repo image path. */\nasync function attachRepoImage(input: { target: string; ctx: CommandContext }): Promise<void> {\n const imagePath = resolveRepoFilePath({\n repoRoot: input.ctx.config.repoPath,\n input: input.target,\n });\n assertImagePath(imagePath);\n if (!input.ctx.orchestrator.attachFiles) {\n console.log(\"Browser file attachment is not available.\");\n return;\n }\n await input.ctx.orchestrator.attachFiles([imagePath]);\n console.log(`Attached image: ${imagePath}`);\n}\n\n/** Capture desktop/mobile screenshots for a URL. */\nasync function handleScreenshot(args: string, ctx: CommandContext): Promise<void> {\n const url = args.trim();\n if (!url) {\n console.log(\"Usage: /screenshot <url>\");\n return;\n }\n const files = await captureUrlScreenshots({ url, repoPath: ctx.config.repoPath });\n printScreenshotPaths(files);\n}\n\n/** Capture UI screenshots and ask ChatGPT to review them. */\nasync function handleUiQa(args: string, ctx: CommandContext): Promise<void> {\n const url = args.trim();\n if (!url) {\n console.log(\"Usage: /ui-qa <url>\");\n return;\n }\n const files = await runUiQaCapture({ url, ctx });\n console.log(`UI QA requested with ${files.length} screenshots.`);\n}\n\n/** Capture screenshots, attach them, and send the review prompt. */\nasync function runUiQaCapture(input: { url: string; ctx: CommandContext }): Promise<string[]> {\n const files = await captureUrlScreenshots({\n url: input.url,\n repoPath: input.ctx.config.repoPath,\n });\n if (input.ctx.orchestrator.attachFiles) await input.ctx.orchestrator.attachFiles(files);\n await sendUiQaPrompt({ url: input.url, files, ctx: input.ctx });\n return files;\n}\n\n/** Print captured screenshot file paths. */\nfunction printScreenshotPaths(files: string[]): void {\n console.log(\"Screenshots:\");\n for (const file of files) console.log(` ${file}`);\n}\n\n/** Inputs for sending a UI QA review prompt. */\ninterface SendUiQaPromptParams {\n /** Reviewed page URL. */\n url: string;\n /** Screenshot file paths. */\n files: string[];\n /** Active command context. */\n ctx: CommandContext;\n}\n\n/** Send UI QA review instructions with screenshot references. */\nasync function sendUiQaPrompt(params: SendUiQaPromptParams): Promise<void> {\n await params.ctx.sendMessage(\n [\n `Review the UI at ${params.url}.`,\n \"I attached desktop and mobile screenshots when the browser supports file attachment.\",\n \"Focus on layout breakage, overlapping text, responsive behavior, accessibility, and concrete fixes.\",\n \"\",\n \"Screenshot files:\",\n ...params.files.map((file) => `- ${file}`),\n ].join(\"\\n\"),\n );\n}\n\n// --- commands/handlers/browser.ts ---\n\n/** Browser and terminal UI slash-command handlers keyed by command name. */\nconst BROWSER_HANDLERS: Record<string, (args: string, ctx: CommandContext) => Promise<void>> = {\n help: handleHelp,\n new: handleNew,\n stop: handleStop,\n compact: handleCompact,\n commands: handleCommands,\n logs: handleLogs,\n status: handleStatus,\n statusline: handleStatusline,\n clear: handleClear,\n \"attach-image\": handleAttachImage,\n screenshot: handleScreenshot,\n \"ui-qa\": handleUiQa,\n diff: handleDiff,\n exit: handleExit,\n};\n\n// --- commands/handlers/session/conversations.ts ---\n\n/** List sidebar conversations or navigate when a query is provided. */\nasync function handleConversations(args: string, ctx: CommandContext): Promise<void> {\n const conversations = await ctx.orchestrator.listConversations();\n if (conversations.length === 0) {\n console.log(\"No conversations found in sidebar.\");\n return;\n }\n if (args.trim()) {\n await openMatchingConversation({ query: args.trim(), conversations, ctx });\n return;\n }\n printConversationList(conversations);\n}\n\n/** Inputs for opening a conversation by id or title fragment. */\ninterface OpenMatchingConversationParams {\n /** User search query. */\n query: string;\n /** Sidebar conversations. */\n conversations: Array<{ id: string; title: string; url: string }>;\n /** Active command context. */\n ctx: CommandContext;\n}\n\n/** Navigate to the first conversation matching the query. */\nasync function openMatchingConversation(params: OpenMatchingConversationParams): Promise<void> {\n const needle = params.query.toLowerCase();\n const match = params.conversations.find(\n (c) => c.id.toLowerCase().includes(needle) || c.title.toLowerCase().includes(needle),\n );\n if (match) {\n console.log(`Navigating to: ${match.title} (${match.id})`);\n await params.ctx.orchestrator.navigateToConversation(match.url);\n return;\n }\n console.log(`No conversation matching \"${params.query}\".`);\n}\n\n/** Print numbered conversation titles for `/resume`. */\nfunction printConversationList(conversations: Array<{ id: string; title: string }>): void {\n console.log(\"\\nChatGPT Conversations:\\n\");\n conversations.forEach((conversation, i) => {\n console.log(` ${String(i + 1).padStart(2)}. ${conversation.title}`);\n });\n console.log(\"\\nUse /resume <number> to continue a conversation.\\n\");\n}\n\n// --- commands/handlers/session/list-sessions.ts ---\n\n/** List local bridge sessions with current-session marker. */\nasync function handleSessions(_args: string, ctx: CommandContext): Promise<void> {\n const sessions = await listSessions(sessionStore(ctx.config.repoPath));\n if (sessions.length === 0) {\n console.log(\"No local bridge sessions found.\");\n return;\n }\n printSessionRows({ sessions, currentId: ctx.session?.getId() });\n}\n\n/** Inputs for printing the session table. */\ninterface PrintSessionRowsParams {\n /** Session metadata rows. */\n sessions: Array<{ id: string; updatedAt: string; model?: string | null; repoPath: string }>;\n /** Currently active session id, if any. */\n currentId?: string;\n}\n\n/** Print up to 20 local sessions with a current-session marker. */\nfunction printSessionRows(params: PrintSessionRowsParams): void {\n console.log(\"\\nLocal sessions:\\n\");\n for (const session of params.sessions.slice(0, 20)) {\n const marker = session.id === params.currentId ? \"*\" : \" \";\n console.log(\n `${marker} ${session.id.padEnd(38)} ${session.updatedAt} ${session.model ?? \"unknown\"} ${session.repoPath}`,\n );\n }\n console.log(\"\\nUse /resume --last or /resume <session-id> to make a session current.\\n\");\n}\n\n// --- commands/handlers/session/resume.ts ---\n\n/** Resume a browser conversation or local bridge session. */\nasync function handleResume(args: string, ctx: CommandContext): Promise<void> {\n const query = args.trim();\n if (!query) {\n console.log(\n \"Usage: /resume <number|title|id> or /resume --last (use /conversations or /sessions)\",\n );\n return;\n }\n if (query === \"--last\") {\n await resumeLatestSession(ctx);\n return;\n }\n if (await resumeLocalSession({ query, ctx })) return;\n await resumeBrowserConversation({ query, ctx });\n}\n\n/** Activate the most recently updated local session. */\nasync function resumeLatestSession(ctx: CommandContext): Promise<void> {\n const latest = await getLatestSession(sessionStore(ctx.config.repoPath));\n if (!latest) {\n console.log(\"No local bridge sessions found.\");\n return;\n }\n await ctx.session?.setId(latest.metadata.id);\n console.log(formatSessionSummary(latest.metadata, ctx.session?.getId()));\n}\n\n/** Inputs for resuming a local session by id fragment. */\ninterface ResumeLocalSessionParams {\n /** Session id or fragment. */\n query: string;\n /** Active command context. */\n ctx: CommandContext;\n}\n\n/** Try to resume a local session; returns true when matched. */\nasync function resumeLocalSession(params: ResumeLocalSessionParams): Promise<boolean> {\n const localSession = await tryLoadSession({\n sessionId: params.query,\n options: sessionStore(params.ctx.config.repoPath),\n });\n if (!localSession) return false;\n await params.ctx.session?.setId(localSession.metadata.id);\n console.log(formatSessionSummary(localSession.metadata, params.ctx.session?.getId()));\n return true;\n}\n\n/** Inputs for resuming a browser sidebar conversation. */\ninterface ResumeBrowserConversationParams {\n /** Number, id, or title fragment. */\n query: string;\n /** Active command context. */\n ctx: CommandContext;\n}\n\n/** Navigate to a numbered or named browser conversation. */\nasync function resumeBrowserConversation(params: ResumeBrowserConversationParams): Promise<void> {\n const conversations = await params.ctx.orchestrator.listConversations();\n const target = findBrowserConversation({ conversations, query: params.query });\n if (!target) {\n console.log(`No conversation matching \"${params.query}\". Use /conversations to see the list.`);\n return;\n }\n console.log(`Resuming: ${target.title}`);\n await params.ctx.orchestrator.navigateToConversation(target.url);\n}\n\n/** Match a browser conversation by number, id, or title fragment. */\nfunction findBrowserConversation(input: {\n conversations: Array<{ id: string; title: string; url: string }>;\n query: string;\n}): { id: string; title: string; url: string } | undefined {\n const num = Number.parseInt(input.query, 10);\n if (Number.isNaN(num)) {\n return input.conversations.find(\n (conversation) =>\n conversation.id.toLowerCase().includes(input.query.toLowerCase()) ||\n conversation.title.toLowerCase().includes(input.query.toLowerCase()),\n );\n }\n return input.conversations[num - 1];\n}\n\n// --- commands/handlers/session/transcript.ts ---\n\n/** Print the local session transcript. */\nasync function handleTranscript(args: string, ctx: CommandContext): Promise<void> {\n const sessionId = await resolveSessionId({ args, ctx });\n if (!sessionId) {\n console.log(\"No local session selected. Use /sessions first.\");\n return;\n }\n const exported = await exportSession(sessionId, sessionStore(ctx.config.repoPath));\n console.log(trimOutput(exported.transcript || \"(empty transcript)\", 40_000));\n}\n\n/** Copy the local session transcript to the clipboard. */\nasync function handleCopy(args: string, ctx: CommandContext): Promise<void> {\n const sessionId = await resolveSessionId({ args, ctx });\n if (!sessionId) {\n console.log(\"No local session selected. Use /sessions first.\");\n return;\n }\n const exported = await exportSession(sessionId, sessionStore(ctx.config.repoPath));\n await copyTextToClipboard(exported.transcript);\n console.log(`Copied transcript for ${sessionId} to clipboard.`);\n}\n\n/** Export the local session transcript to a file. */\nasync function handleExport(args: string, ctx: CommandContext): Promise<void> {\n const selection = await resolveSessionExportArgs({ args, ctx });\n if (!selection.sessionId) {\n console.log(\"No local session selected. Use /sessions first.\");\n return;\n }\n await writeSessionExport({\n sessionId: selection.sessionId,\n outputPath: selection.outputPath,\n ctx,\n });\n}\n\n/** Inputs for writing a session export file. */\ninterface WriteSessionExportParams {\n /** Resolved session id. */\n sessionId: string;\n /** Optional absolute output file path. */\n outputPath?: string;\n /** Active command context. */\n ctx: CommandContext;\n}\n\n/** Write exported session content to disk. */\nasync function writeSessionExport(params: WriteSessionExportParams): Promise<void> {\n const store = sessionStore(params.ctx.config.repoPath);\n const exported = await exportSession(params.sessionId, store);\n const targetPath =\n params.outputPath ??\n defaultExportPath({ repoPath: params.ctx.config.repoPath, sessionId: params.sessionId });\n await persistSessionExport({ targetPath, exported, sessionId: params.sessionId });\n}\n\n/** Create parent dirs and write exported session content. */\nasync function persistSessionExport(input: {\n targetPath: string;\n exported: Awaited<ReturnType<typeof exportSession>>;\n sessionId: string;\n}): Promise<void> {\n const content = exportContentForPath({ path: input.targetPath, exported: input.exported });\n await mkdir(dirname(input.targetPath), { recursive: true });\n await writeFile(input.targetPath, content, \"utf-8\");\n console.log(`Exported ${input.sessionId} to ${input.targetPath}`);\n}\n\n// --- commands/handlers/session/checkpoints.ts ---\n\n/** List file checkpoints for the current repo. */\nasync function handleCheckpoints(_args: string, ctx: CommandContext): Promise<void> {\n const checkpoints = await listCheckpoints({ repoRoot: ctx.config.repoPath });\n if (checkpoints.length === 0) {\n console.log(\"No checkpoints found.\");\n return;\n }\n printCheckpointRows(checkpoints);\n}\n\n/** Print up to 20 checkpoint rows. */\nfunction printCheckpointRows(\n checkpoints: Array<{ id: string; phase: string; fileCount: number; label?: string }>,\n): void {\n console.log(\"\\nCheckpoints:\\n\");\n for (const checkpoint of checkpoints.slice(0, 20)) {\n console.log(\n ` ${checkpoint.id.padEnd(38)} ${checkpoint.phase.padEnd(6)} ${checkpoint.fileCount} files ${checkpoint.label ?? \"\"}`,\n );\n }\n console.log(\"\\nUse /restore <checkpoint-id> or /rewind --files <checkpoint-id>.\\n\");\n}\n\n/** Restore files from a checkpoint, optionally scoped to paths. */\nasync function handleRestore(args: string, ctx: CommandContext): Promise<void> {\n const parts = splitArgs(args);\n const checkpointId = parts[0];\n if (!checkpointId) {\n console.log(\"Usage: /restore <checkpoint-id> [path ...]\");\n return;\n }\n const restored = await restoreCheckpoint({\n repoRoot: ctx.config.repoPath,\n checkpointId,\n paths: parts.slice(1),\n });\n console.log(\n `Restored checkpoint ${checkpointId}: ${restored.restored.length} restored, ${restored.removed.length} removed.`,\n );\n}\n\n/** Rewind the last prompt and/or restore checkpoint files. */\nasync function handleRewind(args: string, ctx: CommandContext): Promise<void> {\n const parts = splitArgs(args);\n if (parts[0] === \"--files\" || parts[0] === \"--both\") {\n await rewindWithCheckpoint({ mode: parts[0], parts, ctx });\n return;\n }\n const replacement = args.trim() || undefined;\n await ctx.orchestrator.rewindLastPrompt(replacement);\n console.log(replacement ? \"Rewound with replacement prompt.\" : \"Rewound the last prompt.\");\n}\n\n/** Inputs for checkpoint-aware rewind. */\ninterface RewindWithCheckpointParams {\n /** `--files` or `--both` mode flag. */\n mode: string;\n /** Parsed command tokens. */\n parts: string[];\n /** Active command context. */\n ctx: CommandContext;\n}\n\n/** Restore checkpoint files and optionally rewind the last prompt. */\nasync function rewindWithCheckpoint(params: RewindWithCheckpointParams): Promise<void> {\n const checkpointId = params.parts[1];\n if (!checkpointId) {\n console.log(`Usage: /rewind ${params.mode} <checkpoint-id> [replacement prompt]`);\n return;\n }\n await restoreAndMaybeRewind(params, checkpointId);\n}\n\n/** Restore checkpoint files and optionally rewind with a replacement prompt. */\nasync function restoreAndMaybeRewind(\n params: RewindWithCheckpointParams,\n checkpointId: string,\n): Promise<void> {\n const restored = await restoreCheckpoint({ repoRoot: params.ctx.config.repoPath, checkpointId });\n console.log(\n `Restored checkpoint ${checkpointId}: ${restored.restored.length} restored, ${restored.removed.length} removed.`,\n );\n if (params.mode === \"--files\") return;\n await rewindPromptAfterRestore(params);\n}\n\n/** Rewind the last prompt after checkpoint restore in `--both` mode. */\nasync function rewindPromptAfterRestore(params: RewindWithCheckpointParams): Promise<void> {\n const replacement = params.parts.slice(2).join(\" \").trim() || undefined;\n await params.ctx.orchestrator.rewindLastPrompt(replacement);\n console.log(\n replacement\n ? \"Restored files and rewound with replacement prompt.\"\n : \"Restored files and rewound the last prompt.\",\n );\n}\n\n// --- commands/handlers/session.ts ---\n\n/** Session-related slash-command handlers keyed by command name. */\nconst SESSION_HANDLERS: Record<string, (args: string, ctx: CommandContext) => Promise<void>> = {\n conversations: handleConversations,\n resume: handleResume,\n sessions: handleSessions,\n transcript: handleTranscript,\n copy: handleCopy,\n export: handleExport,\n checkpoints: handleCheckpoints,\n restore: handleRestore,\n rewind: handleRewind,\n};\n\n// --- commands/handlers/mcp/connector.ts ---\n\n/** Show MCP connector setup and exposed tools. */\nasync function handleMcp(_args: string, ctx: CommandContext): Promise<void> {\n if (normalizeProvider(ctx.config.provider) === \"gemini\") {\n printGeminiMcpDiagnostics();\n return;\n }\n console.log(formatMcpDiagnostics(ctx));\n}\n\n/** Print Gemini MCP limitation diagnostics. */\nfunction printGeminiMcpDiagnostics(): void {\n console.log(\n [\n \"MCP bridge diagnostics:\",\n \"Provider: Gemini web\",\n \"Local MCP tools are not available in gemini.google.com.\",\n \"Use @file mentions to inline repo files into prompts.\",\n \"\",\n \"For full MCP on Gemini, use the official Gemini API or Gemini CLI instead of the browser UI.\",\n ].join(\"\\n\"),\n );\n}\n\n/** Open ChatGPT MCP connector setup in the browser. */\nasync function handleConnector(_args: string, ctx: CommandContext): Promise<void> {\n if (normalizeProvider(ctx.config.provider) === \"gemini\") {\n printGeminiConnectorWarning();\n return;\n }\n const connector = mcpConnectorUrl(ctx.config.tunnelUrl);\n if (!connector) {\n printMissingConnectorUrl(ctx);\n return;\n }\n await openConnectorSetup({ connector, ctx });\n}\n\n/** Print Gemini connector limitation message. */\nfunction printGeminiConnectorWarning(): void {\n console.log(\n \"Gemini web has no custom MCP connector UI. Use @file mentions for read-only repo context, or run with --provider chatgpt for full MCP tools.\",\n );\n}\n\n/** Print guidance when no public connector URL exists. */\nfunction printMissingConnectorUrl(ctx: CommandContext): void {\n console.log(\n [\n \"No public connector URL is available.\",\n `Local MCP server: http://localhost:${ctx.config.mcpPort}`,\n \"ChatGPT cannot normally reach localhost from the browser connector.\",\n \"Restart the bridge and fix Cloudflare Tunnel, then run /connector again.\",\n ].join(\"\\n\"),\n );\n}\n\n/** Run browser connector setup automation when available. */\nasync function openConnectorSetup(params: {\n connector: string;\n ctx: CommandContext;\n}): Promise<void> {\n console.log(formatMcpDiagnostics(params.ctx));\n if (!params.ctx.orchestrator.openConnectorSetup) {\n console.log(\n \"\\nBrowser setup automation is unavailable. Open ChatGPT Settings -> Apps -> Advanced settings -> Create app and paste the Connector URL.\",\n );\n return;\n }\n const result = await params.ctx.orchestrator.openConnectorSetup({\n connectorUrl: params.connector,\n });\n console.log(formatConnectorSetupResult(result));\n}\n\n// --- commands/handlers/mcp/permissions.ts ---\n\n/** Show or switch MCP permission mode. */\nasync function handlePermissions(args: string, ctx: CommandContext): Promise<void> {\n const next = args.trim();\n if (!next) {\n printPermissionModes(ctx);\n return;\n }\n await setPermissionMode({ next, ctx });\n}\n\n/** Print current permission mode and available values. */\nfunction printPermissionModes(ctx: CommandContext): void {\n console.log(\n `Permission mode: ${ctx.permission?.getMode() ?? ctx.config.permissionMode ?? \"auto\"}`,\n );\n console.log(`Available: ${PERMISSION_MODES.join(\", \")}`);\n}\n\n/** Apply a new permission mode when valid. */\nasync function setPermissionMode(params: { next: string; ctx: CommandContext }): Promise<void> {\n const mode = normalizePermissionMode(params.next);\n if (mode !== params.next) {\n console.log(\n `Unknown permission mode \"${params.next}\". Available: ${PERMISSION_MODES.join(\", \")}`,\n );\n return;\n }\n await params.ctx.permission?.setMode(mode);\n params.ctx.config.permissionMode = mode;\n console.log(`Permission mode set to ${mode}.`);\n}\n\n// --- commands/handlers/mcp/task.ts ---\n\n/** Send a project-agent task with MCP tool instructions. */\nasync function handleTask(args: string, ctx: CommandContext): Promise<void> {\n const task = args.trim();\n if (!task) {\n console.log(\"Usage: /task <project task>\");\n return;\n }\n if (normalizeProvider(ctx.config.provider) === \"gemini\") {\n printGeminiTaskWarning();\n return;\n }\n const instructions = await loadProjectInstructions(ctx.config.repoPath);\n await ctx.sendMessage(buildProjectTaskPromptWithInstructions(task, ctx, instructions.promptText));\n}\n\n/** Print Gemini-specific `/task` limitation message. */\nfunction printGeminiTaskWarning(): void {\n console.log(\n \"Gemini web does not support MCP connectors. /task needs live repo tools — use ChatGPT, or send a normal prompt with @file mentions on Gemini.\",\n );\n}\n\n/** Ask ChatGPT to review local repository changes. */\nasync function handleReview(args: string, ctx: CommandContext): Promise<void> {\n const scope = args.trim() || \"working\";\n await ctx.sendMessage(\n [\n \"Review the local repository changes with a code-review stance.\",\n \"Prioritize bugs, regressions, security risks, and missing tests.\",\n \"Use the MCP tools to inspect the repo and diff before making claims.\",\n `Review scope: ${scope}`,\n ].join(\"\\n\"),\n );\n}\n\n// --- commands/handlers/mcp.ts ---\n\n/** MCP-related slash-command handlers keyed by command name. */\nconst MCP_HANDLERS: Record<string, (args: string, ctx: CommandContext) => Promise<void>> = {\n task: handleTask,\n permissions: handlePermissions,\n mcp: handleMcp,\n connector: handleConnector,\n review: handleReview,\n};\n\n// --- commands/handlers/model.ts ---\n\n/** Show or switch the ChatGPT model. */\nasync function handleModel(args: string, ctx: CommandContext): Promise<void> {\n const query = args.trim();\n if (query) {\n await switchModel({ query, ctx });\n return;\n }\n await showCurrentModel(ctx);\n}\n\n/** Switch model and print context estimate update. */\nasync function switchModel(params: { query: string; ctx: CommandContext }): Promise<void> {\n const model = await params.ctx.orchestrator.switchModel(params.query);\n params.ctx.counter.setModel(model);\n const profile = findModelProfile(model);\n console.log(\n `Model switched to ${model}. Context estimate now uses ${profile.contextWindow.toLocaleString()} tokens.`,\n );\n}\n\n/** Print current model details and available browser models. */\nasync function showCurrentModel(ctx: CommandContext): Promise<void> {\n const current = await ctx.orchestrator.detectModel();\n ctx.counter.setModel(current);\n printModelProfile(current);\n await printAvailableModels(ctx);\n}\n\n/** Print browser models or static known profiles. */\nasync function printAvailableModels(ctx: CommandContext): Promise<void> {\n const available = await ctx.orchestrator.listModels();\n if (available.length > 0) {\n printBrowserModels(available);\n return;\n }\n printKnownProfiles();\n}\n\n/** Print context profile for a model name. */\nfunction printModelProfile(model: string): void {\n const profile = findModelProfile(model);\n console.log(`\\nCurrent model: ${model}`);\n console.log(`Context window: ${profile.contextWindow.toLocaleString()} tokens`);\n if (profile.maxOutputTokens) {\n console.log(`Max output: ${profile.maxOutputTokens.toLocaleString()} tokens`);\n }\n console.log(`Source: ${profile.sourceUrl}`);\n}\n\n/** Print browser model picker entries. */\nfunction printBrowserModels(models: Array<{ label: string; selected?: boolean }>): void {\n console.log(\"\\nBrowser models:\");\n for (const model of models) {\n console.log(` ${model.selected ? \"*\" : \" \"} ${model.label}`);\n }\n console.log(\"\\nUse /model <name> to switch.\");\n}\n\n/** Print static known context profiles. */\nfunction printKnownProfiles(): void {\n console.log(\"\\nKnown context profiles:\");\n for (const model of listModelProfiles()) {\n console.log(` ${model.label.padEnd(24)} ${model.contextWindow.toLocaleString()} ctx`);\n }\n}\n\n/** Show context window usage for the active model. */\nasync function handleContext(_args: string, ctx: CommandContext): Promise<void> {\n console.log(`Context estimate for ${ctx.counter.modelLabel}: ${ctx.counter.summary}`);\n}\n\n/** Model-related slash-command handlers keyed by command name. */\nconst MODEL_HANDLERS: Record<string, (args: string, ctx: CommandContext) => Promise<void>> = {\n model: handleModel,\n context: handleContext,\n};\n\n// --- commands/registry.helpers.ts ---\n\n/** Run a built-in handler and report failures without throwing. */\nasync function executeBuiltinCommand(input: {\n parsed: { name: string; args: string };\n cmd: CommandDef;\n ctx: CommandContext;\n}): Promise<boolean> {\n try {\n await input.cmd.handler(input.parsed.args, input.ctx);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`Command /${input.parsed.name} failed: ${message}`);\n }\n return true;\n}\n\n/** Resolve and run a user-defined custom command. */\nasync function executeCustomCommand(input: {\n parsed: { name: string; args: string };\n ctx: CommandContext;\n}): Promise<boolean> {\n const custom = await findCustomCommand({ name: input.parsed.name, ctx: input.ctx });\n if (!custom) return false;\n await input.ctx.sendMessage(renderCustomCommandPrompt(custom, input.parsed.args));\n return true;\n}\n\n/** Split a raw `/name args...` string into its name and argument remainder. */\nfunction parseCommandInput(input: string): { name: string; args: string } | null {\n const trimmed = input.trim();\n if (!trimmed.startsWith(\"/\")) return null;\n const { name, args } = splitCommandNameAndArgs(trimmed);\n if (!name) return null;\n return { name, args };\n}\n\n/** Extract command name and args from a trimmed slash input string. */\nfunction splitCommandNameAndArgs(trimmed: string): { name: string; args: string } {\n const spaceIdx = trimmed.indexOf(\" \");\n const name = spaceIdx === -1 ? trimmed.slice(1) : trimmed.slice(1, spaceIdx);\n const args = spaceIdx === -1 ? \"\" : trimmed.slice(spaceIdx + 1);\n return { name, args };\n}\n\n/** Look up a project/user custom command by name. */\nasync function findCustomCommand(input: { name: string; ctx: CommandContext }) {\n const custom = await loadCustomCommands({ repoRoot: input.ctx.config.repoPath });\n return custom.find((command) => command.name === input.name);\n}\n\n// --- commands/builtins.ts ---\n\n/** Handler lookup table keyed by slash-command name. */\ntype CommandHandlerMap = Record<string, CommandDef[\"handler\"]>;\n\n/** Inputs for composing command definitions from metadata and handlers. */\ninterface ComposeCommandsInput {\n /** Command metadata entries. */\n meta: CommandMeta[];\n /** Handler map keyed by command name. */\n handlers: CommandHandlerMap;\n}\n\n/**\n * Compose {@link CommandDef} entries from metadata arrays and handler maps.\n * Keeps `builtins.ts` thin while `commands.config.ts` stays function-free.\n */\nfunction composeCommands(input: ComposeCommandsInput): CommandDef[] {\n return input.meta.flatMap((entry) => {\n const handler = input.handlers[entry.name];\n if (!handler) return [];\n return [{ name: entry.name, description: entry.description, aliases: entry.aliases, handler }];\n });\n}\n\n/** Built-in slash commands registered at startup via `registry.ts`. */\nconst BUILTIN_COMMANDS: CommandDef[] = [\n filesCommand,\n ...composeCommands({ meta: SESSION_COMMANDS, handlers: SESSION_HANDLERS }),\n ...composeCommands({ meta: MODEL_COMMANDS, handlers: MODEL_HANDLERS }),\n ...composeCommands({ meta: MCP_COMMANDS, handlers: MCP_HANDLERS }),\n ...composeCommands({ meta: BROWSER_COMMANDS, handlers: BROWSER_HANDLERS }),\n];\n\n// --- commands/registry.ts ---\n\n/**\n * Slash-command dispatch: the registry Map plus lookup/execution. The actual\n * command catalog lives in `builtins.ts` and `commands.config.ts` (imported\n * below) and custom user\n * commands are resolved on demand from markdown files. Importing this module\n * registers all built-ins as a side effect, so consumers only need to import\n * {@link executeCommand} / {@link getAllCommands} to get a working command set.\n */\n\nconst commands = new Map<string, CommandDef>();\nconst canonicalNames = new Set<string>();\n\n/** Register a command under its name and any aliases. */\nfunction registerCommand(cmd: CommandDef): void {\n commands.set(cmd.name, cmd);\n canonicalNames.add(cmd.name);\n for (const alias of cmd.aliases ?? []) {\n commands.set(alias, cmd);\n }\n}\n\n/** Get all registered, non-hidden commands (for autocomplete and `/help`). */\nfunction getAllCommands(): CommandDef[] {\n return [...canonicalNames]\n .map((name) => commands.get(name))\n .filter((cmd): cmd is CommandDef => !!cmd && !cmd.hidden);\n}\n\n/** Parse input as a registered command, or null if it is not a known command string. */\nfunction parseCommand(input: string): { name: string; args: string } | null {\n const parsed = parseCommandInput(input);\n if (!parsed || !commands.has(parsed.name)) return null;\n return parsed;\n}\n\n/**\n * Execute a command, returning true if the input was handled.\n *\n * Falls back to project/user custom commands (markdown templates) when the name\n * is not a built-in, and reports handler errors without throwing.\n */\nasync function executeCommand(input: string, ctx: CommandContext): Promise<boolean> {\n const parsed = parseCommandInput(input);\n if (!parsed) return false;\n const cmd = commands.get(parsed.name);\n if (!cmd) return executeCustomCommand({ parsed, ctx });\n return executeBuiltinCommand({ parsed, cmd, ctx });\n}\n\n/** Filter commands whose name starts with the partial text after the `/`. */\nfunction matchCommands(partial: string): CommandDef[] {\n const q = partial.toLowerCase();\n return getAllCommands().filter((cmd) => cmd.name.toLowerCase().startsWith(q));\n}\n\nfor (const command of BUILTIN_COMMANDS) {\n registerCommand(command);\n}\n\n// --- headless/shared.ts ---\n\n/** Fatal error helper: write to stderr and exit non-zero. */\nfunction fail(message: string): never {\n process.stderr.write(`${message}\\n`);\n process.exit(1);\n}\n\n/** Redirect console.log to stderr so stdout stays machine-readable. */\nfunction redirectConsoleToStderr(): void {\n console.log = (...args: unknown[]) => console.error(...args);\n console.info = (...args: unknown[]) => console.error(...args);\n console.debug = (...args: unknown[]) => console.error(...args);\n}\n\n/**\n * Convert a CLI `--timeout <seconds>` string to milliseconds for the engine.\n * Returns undefined for absent/empty/NaN/non-positive input so the browser\n * layer falls back to its default wait.\n */\nfunction timeoutMsFromSeconds(seconds: string | undefined): number | undefined {\n if (!seconds) return undefined;\n const parsed = Number(seconds);\n if (Number.isNaN(parsed) || parsed <= 0) return undefined;\n return Math.round(parsed * 1000);\n}\n\n/**\n * Stop the in-flight ChatGPT turn, tear the engine down, then exit. Used by the\n * headless signal handlers so a Ctrl-C / kill clicks \"Stop generating\" before\n * dropping the process — otherwise ChatGPT keeps generating server-side in the\n * warm tab and burns Plus quota on a reply nobody captures.\n */\nasync function abortAndExit(\n engine: BridgeEngine,\n code: number,\n exit: (code: number) => never,\n): Promise<void> {\n await engine\n .getOrchestrator()\n .stopResponse()\n .catch(() => {});\n await engine.shutdown({ closeBrowser: false }).catch(() => {});\n exit(code);\n}\n\n/** Print stored bridge sessions (newest first) as JSON. */\nasync function runSessionsCmd(): Promise<void> {\n const sessions = await listSessions();\n process.stdout.write(`${JSON.stringify(sessions, null, 2)}\\n`);\n process.exit(0);\n}\n\n/** Kill whatever process is listening on the Chrome debug port (macOS `lsof`). */\nfunction killDebugPort(port: number): Promise<boolean> {\n return new Promise((resolveKill) => {\n execFile(\"lsof\", [\"-ti\", `tcp:${port}`], (...args: [Error | null, string]) => {\n resolveKill(killPidsFromStdout(args[1]));\n });\n });\n}\n\n/** Parse lsof stdout and kill each pid (best-effort). */\nfunction killPidsFromStdout(stdout: string): boolean {\n const pids = stdout.trim().split(/\\s+/).filter(Boolean);\n if (pids.length === 0) return false;\n for (const pid of pids) killPidBestEffort(pid);\n return true;\n}\n\n/** Kill one pid, ignoring errors when the process is already gone. */\nfunction killPidBestEffort(pid: string): void {\n try {\n process.kill(Number(pid));\n } catch {\n // process already gone\n }\n}\n\n// --- headless/ask.output.helpers.ts ---\n\n/** Ensure the browser is connected and signed in, or exit with guidance. */\nasync function assertSignedIn(\n engine: Awaited<ReturnType<typeof startEngine>>,\n browserProvider: ReturnType<typeof getBrowserProvider>,\n provider: ReturnType<typeof normalizeProvider>,\n): Promise<void> {\n const browser = engine.browser;\n if (!browser) {\n await engine.shutdown({ closeBrowser: false });\n fail(`Browser not connected. Run \\`bridge login --provider ${provider}\\` once to sign in.`);\n }\n try {\n await browserProvider.assertSignedIn(browser.getPage());\n } catch (err) {\n await engine.shutdown({ closeBrowser: false });\n fail(err instanceof Error ? err.message : String(err));\n }\n}\n\n/** Inputs for {@link writeAskOutput}. */\ninterface WriteAskOutputContext {\n /** Engine whose session/model/counter back the JSON payload. */\n engine: Awaited<ReturnType<typeof startEngine>>;\n /** Captured assistant reply, or null when the turn produced nothing. */\n reply: Awaited<ReturnType<Awaited<ReturnType<typeof startEngine>>[\"ask\"]>>;\n /** Real orchestrator failure captured during the turn, if any. */\n orchestratorError: string | null;\n /** Parsed ask options (controls JSON vs plain output). */\n options: AskOptions;\n /** Normalized provider id used in the login hint. */\n provider: ReturnType<typeof normalizeProvider>;\n /** Human-readable provider name used in the login hint. */\n displayName: string;\n}\n\n/**\n * Write the ask reply as plain text or JSON, or exit when no reply was captured.\n *\n * On a null reply, prefer the real orchestrator error (e.g. a send timeout) over\n * the generic login hint, which previously masked every failure as a sign-in\n * problem even when ChatGPT had replied in the browser.\n */\nfunction writeAskOutput(ctx: WriteAskOutputContext): void {\n if (!ctx.reply) {\n fail(\n ctx.orchestratorError ??\n `No reply captured — ${ctx.displayName} may not be logged in, or the page UI changed. Try \\`bridge login --provider ${ctx.provider}\\`.`,\n );\n }\n if (ctx.options.json) {\n process.stdout.write(\n `${JSON.stringify({\n sessionId: ctx.engine.sessionId,\n model: ctx.engine.getOrchestrator().model,\n reply: ctx.reply.content,\n contextTokens: ctx.engine.counter.count,\n })}\\n`,\n );\n return;\n }\n process.stdout.write(`${ctx.reply.content}\\n`);\n}\n\n// --- headless/ask.helpers.ts ---\n\n/** Inputs for starting the ask engine. */\ninterface StartAskEngineInput {\n /** CLI ask options. */\n options: AskOptions;\n /** Normalized provider id. */\n provider: ReturnType<typeof normalizeProvider>;\n /** Whether the provider supports MCP connector tooling. */\n supportsMcpConnector: boolean;\n}\n\n/** Run the full headless ask flow and exit. Fans out when --provider is a comma list. */\nasync function runAskFlow(input: { prompt: string; options: AskOptions }): Promise<void> {\n const providers = resolveProviderListOrFail(input.options.provider);\n if (providers.length > 1) {\n return runFanoutAsk({ prompt: input.prompt, providers, options: input.options });\n }\n redirectConsoleToStderr();\n const setup = await prepareAskRun(input.options);\n const captured = captureOrchestratorError(setup.engine);\n const reply = await runAskTurn({\n engine: setup.engine,\n prompt: input.prompt,\n options: input.options,\n });\n await finishAskRun({\n setup,\n reply,\n orchestratorError: captured.lastError(),\n options: input.options,\n });\n}\n\n/** Parse a comma-separated --provider list, or exit cleanly on an unknown provider. */\nfunction resolveProviderListOrFail(spec: string | undefined): BridgeProviderId[] {\n try {\n return parseProviderList(spec);\n } catch (err) {\n fail(err instanceof Error ? err.message : String(err));\n }\n}\n\n/**\n * Fan one prompt out across several providers (one tab each) and print a per-provider\n * JSON map (or a labelled block per provider), exiting per {@link fanoutFailed}.\n *\n * LIVE-VERIFY: each provider reuses the single-ask machinery via {@link askOneProvider};\n * the concurrent multi-tab behaviour needs checking against real signed-in sessions.\n */\nasync function runFanoutAsk(input: {\n prompt: string;\n providers: BridgeProviderId[];\n options: AskOptions;\n}): Promise<void> {\n redirectConsoleToStderr();\n const timeoutMs = timeoutMsFromSeconds(input.options.timeout);\n const result = await fanoutAsk(\n input.providers,\n (provider) => askOneProvider(provider as BridgeProviderId, input.prompt, input.options),\n timeoutMs ? { timeoutMs } : {},\n );\n writeFanoutOutput(result, input.options);\n process.exit(fanoutFailed(result, Boolean(input.options.strict)) ? 1 : 0);\n}\n\n/** Run a single-provider ask in isolation and return its reply text (throws on failure). */\nasync function askOneProvider(\n provider: BridgeProviderId,\n prompt: string,\n options: AskOptions,\n): Promise<string> {\n const browserProvider = getBrowserProvider(provider);\n const engine = await startAskEngine({\n options: { ...options, provider },\n provider,\n supportsMcpConnector: browserProvider.supportsMcpConnector,\n });\n try {\n const browser = engine.browser;\n if (!browser) {\n throw new Error(\n `Browser not connected. Run \\`bridge login --provider ${provider}\\` once to sign in.`,\n );\n }\n await browserProvider.assertSignedIn(browser.getPage());\n const captured = captureOrchestratorError(engine);\n const reply = await runAskTurn({ engine, prompt, options: { ...options, provider } });\n if (!reply) {\n throw new Error(captured.lastError() ?? `${browserProvider.displayName}: no reply captured.`);\n }\n return reply.content;\n } finally {\n await engine.shutdown({ closeBrowser: false }).catch(() => {});\n }\n}\n\n/** Print a fan-out result as keyed JSON (--json) or a labelled block per provider. */\nfunction writeFanoutOutput(result: FanoutResult, options: AskOptions): void {\n if (options.json) {\n process.stdout.write(`${JSON.stringify(result)}\\n`);\n return;\n }\n for (const [provider, outcome] of Object.entries(result)) {\n const status = outcome.ok ? \"ok\" : \"error\";\n const body = outcome.ok ? (outcome.reply ?? \"\") : (outcome.error ?? \"\");\n process.stdout.write(`=== ${provider} (${status}, ${outcome.elapsedMs}ms) ===\\n${body}\\n\\n`);\n }\n}\n\n/**\n * Serve the outbound MCP `ask` gateway over stdio so other agents can drive one or more\n * web chats as a native tool. Each `ask` call fans out via {@link askOneProvider}, so the\n * warm browser is shared across calls and one slow provider never blocks the rest.\n *\n * Console output is redirected to stderr first: stdout is the JSON-RPC channel, and any\n * engine/browser log written there would corrupt the protocol stream.\n */\nexport async function runServe(options: ServeOptions): Promise<void> {\n redirectConsoleToStderr();\n const base: AskOptions = { repo: options.repo, port: options.port, timeout: options.timeout };\n const deps: AskGatewayDeps = {\n runFanout: (providers, prompt, opts) =>\n fanoutAsk(\n providers,\n (provider) => askOneProvider(provider as BridgeProviderId, prompt, base),\n opts.timeoutMs ? { timeoutMs: opts.timeoutMs } : {},\n ),\n };\n await serveAskGatewayStdio(deps);\n}\n\n/**\n * Subscribe to orchestrator error events for a headless ask so a null reply can\n * report the real failure cause instead of the generic \"not logged in\" hint.\n *\n * `sendPrompt` emits `{ type: \"error\" }` and resolves to null on failure, so the\n * headless path would otherwise lose the actual reason (e.g. a send timeout).\n * Read `lastError()` after the ask turn and before shutdown to capture it.\n */\nfunction captureOrchestratorError(engine: Awaited<ReturnType<typeof startEngine>>): {\n lastError: () => string | null;\n} {\n let lastError: string | null = null;\n engine.getOrchestrator().on((event) => {\n if (event.type === \"error\") lastError = event.error;\n });\n return { lastError: () => lastError };\n}\n\n/** Start engine, register signals, and verify sign-in. */\nasync function prepareAskRun(options: AskOptions) {\n const providers = resolveAskProviders(options);\n const engine = await startAskEngine({\n options,\n provider: providers.provider,\n supportsMcpConnector: providers.browserProvider.supportsMcpConnector,\n });\n registerAskSignalHandlers(engine);\n await assertSignedIn(engine, providers.browserProvider, providers.provider);\n return { engine, ...providers };\n}\n\n/** Resolve normalized provider and browser provider for ask runs. */\nfunction resolveAskProviders(options: AskOptions) {\n const provider = normalizeProvider(options.provider);\n return { provider, browserProvider: getBrowserProvider(provider) };\n}\n\n/** Shut down engine, write output, and exit. */\nasync function finishAskRun(input: {\n setup: Awaited<ReturnType<typeof prepareAskRun>>;\n reply: Awaited<ReturnType<Awaited<ReturnType<typeof startEngine>>[\"ask\"]>>;\n orchestratorError: string | null;\n options: AskOptions;\n}): Promise<void> {\n await input.setup.engine.shutdown({ closeBrowser: false });\n writeAskOutput({\n engine: input.setup.engine,\n reply: input.reply,\n orchestratorError: input.orchestratorError,\n options: input.options,\n provider: input.setup.provider,\n displayName: input.setup.browserProvider.displayName,\n });\n process.exit(0);\n}\n\n/** Start the engine for a headless ask run. */\nasync function startAskEngine(input: StartAskEngineInput) {\n return startEngine({\n repoPath: input.options.repo ? resolve(input.options.repo) : undefined,\n provider: input.provider,\n mcpPort: input.options.port ? Number(input.options.port) : undefined,\n withBrowser: true,\n withTools: Boolean(input.options.tools) && input.supportsMcpConnector,\n });\n}\n\n/** Register SIGINT/SIGTERM handlers that abort the in-flight turn. */\nfunction registerAskSignalHandlers(engine: Awaited<ReturnType<typeof startEngine>>): void {\n process.once(\"SIGINT\", () => void abortAndExit(engine, 130, process.exit));\n process.once(\"SIGTERM\", () => void abortAndExit(engine, 143, process.exit));\n}\n\n/** Parse the --images count into a positive integer, or undefined when unset or invalid. */\nfunction imageCountFromOption(value: string | undefined): number | undefined {\n if (value === undefined) return undefined;\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n}\n\n/** Apply preflight options and send the ask prompt. */\nasync function runAskTurn(input: {\n engine: Awaited<ReturnType<typeof startEngine>>;\n prompt: string;\n options: AskOptions;\n}) {\n await applyAskPreflight({ engine: input.engine, options: input.options });\n await attachAskFiles({ engine: input.engine, options: input.options });\n return input.engine.ask({\n content: input.prompt,\n timeoutMs: timeoutMsFromSeconds(input.options.timeout),\n expectImages: imageCountFromOption(input.options.images),\n });\n}\n\n/** Attach repo-relative images before the prompt when --attach is set. */\nasync function attachAskFiles(input: {\n engine: Awaited<ReturnType<typeof startEngine>>;\n options: AskOptions;\n}): Promise<void> {\n const paths = input.options.attach;\n if (!paths?.length) return;\n const repoRoot = resolve(input.options.repo ?? process.cwd());\n const resolved = paths.map((target) => {\n const rel = resolveRepoFilePath({ repoRoot, input: target });\n assertImagePath(rel);\n return resolve(repoRoot, rel);\n });\n await input.engine.getOrchestrator().attachFiles(resolved);\n}\n\n/** Resolve a conversation flag to a ChatGPT thread URL. */\nfunction conversationUrlFromOption(value: string): string {\n return conversationUrlFromIdOrUrl(value);\n}\n\n/** Navigate to a conversation only when the active tab is on a different thread. */\nasync function navigateToConversationIfNeeded(input: {\n engine: Awaited<ReturnType<typeof startEngine>>;\n conversation?: string;\n page: Page;\n}): Promise<void> {\n if (!input.conversation) return;\n const targetUrl = conversationUrlFromOption(input.conversation);\n if (isSameChatGptConversation(input.page.url(), targetUrl)) return;\n await input.engine\n .getOrchestrator()\n .navigateToConversation(targetUrl)\n .catch(() => {});\n}\n\n/** Apply --fresh, --conversation, and --model preflight options before asking. */\nasync function applyAskPreflight(input: {\n engine: Awaited<ReturnType<typeof startEngine>>;\n options: AskOptions;\n}): Promise<void> {\n if (input.options.fresh)\n await input.engine\n .getOrchestrator()\n .newConversation()\n .catch(() => {});\n else if (input.options.conversation) {\n await input.engine\n .getOrchestrator()\n .navigateToConversation(conversationUrlFromOption(input.options.conversation))\n .catch(() => {});\n }\n if (input.options.model)\n await input.engine\n .getOrchestrator()\n .switchModel(input.options.model)\n .catch(() => {});\n}\n\n// --- headless/download.helpers.ts ---\n\n/** Reject Gemini until attachment download is supported there. */\nfunction assertDownloadProviderSupported(options: DownloadCmdOptions): void {\n if (normalizeProvider(options.provider) === \"gemini\") {\n fail(\"Attachment download is not supported for Gemini web yet. Use ChatGPT for /download.\");\n }\n}\n\n/** Download attachments with optional output dir and id filter. */\nasync function downloadConversationAttachments(input: {\n page: Page;\n conversationId: string;\n options: DownloadCmdOptions;\n}): Promise<DownloadResult[]> {\n const ids = parseAttachmentIds(input.options.id);\n return downloadAll(input.page, input.conversationId, {\n repoRoot: resolve(input.options.repo ?? process.cwd()),\n ...(input.options.out ? { outDir: input.options.out } : {}),\n ...(ids ? { ids } : {}),\n });\n}\n\n/** Write download results as JSON or human-readable lines. */\nfunction writeDownloadOutput(results: DownloadResult[], json?: boolean): void {\n if (json) {\n process.stdout.write(`${JSON.stringify(results)}\\n`);\n return;\n }\n for (const result of results) {\n const line = `${formatDownloadLine(result)}\\n`;\n if (result.error) process.stderr.write(line);\n else process.stdout.write(line);\n }\n}\n\n/**\n * Flatten repeated `--id` flags into a clean id list.\n * Returns `undefined` when nothing remains so callers can omit `ids`.\n */\nfunction parseAttachmentIds(values: string[] | undefined): string[] | undefined {\n if (!values) return undefined;\n const ids = values\n .flatMap((value) => value.split(/[\\s,]+/))\n .map((id) => id.trim())\n .filter(Boolean);\n return ids.length > 0 ? ids : undefined;\n}\n\n/** Render one download result as a human-readable line for the terminal. */\nfunction formatDownloadLine(result: DownloadResult): string {\n const label = result.id ?? \"attachment\";\n if (result.error) return `${label}: ${result.error}`;\n return `${label} -> ${result.path} (${result.bytes} bytes)`;\n}\n\n// --- headless/download.ts ---\n\n/** Download a conversation's attachments to disk without the TUI. */\nasync function runDownloadCmd(options: DownloadCmdOptions): Promise<void> {\n assertDownloadProviderSupported(options);\n redirectConsoleToStderr();\n const results = await runDownloadFlow(options);\n writeDownloadOutput(results, options.json);\n process.exit(0);\n}\n\n/** Start engine, extract messages, and download attachments. */\nasync function runDownloadFlow(options: DownloadCmdOptions): Promise<DownloadResult[]> {\n const context = await prepareDownloadContext(options);\n const results = await downloadAfterExtract(context);\n await context.engine.shutdown({ closeBrowser: false });\n return results;\n}\n\n/** Start engine and resolve page plus conversation id. */\nasync function prepareDownloadContext(options: DownloadCmdOptions) {\n const engine = await startDownloadEngine(options);\n const page = requireBrowserPage(engine);\n return {\n engine,\n page,\n conversationId: options.conversation ?? conversationIdFromPage(page),\n options,\n };\n}\n\n/** Download attachments with optional output dir and id filter. */\nasync function downloadAfterExtract(input: {\n page: Page;\n conversationId: string;\n options: DownloadCmdOptions;\n engine: Awaited<ReturnType<typeof startDownloadEngine>>;\n}): Promise<DownloadResult[]> {\n await navigateToConversationIfNeeded({\n engine: input.engine,\n conversation: input.options.conversation,\n page: input.page,\n });\n await extractAllMessages(input.page, { conversationId: input.conversationId });\n if (input.options.scan) {\n const manifest = await loadManifest(input.conversationId);\n process.stderr.write(\n `Manifest refreshed: ${manifest.attachments.length} attachment(s) for ${input.conversationId}\\n`,\n );\n return [];\n }\n return downloadConversationAttachments(input);\n}\n\n/** Start the engine for a headless download run. */\nasync function startDownloadEngine(options: DownloadCmdOptions) {\n return startEngine({\n repoPath: options.repo ? resolve(options.repo) : undefined,\n provider: normalizeProvider(options.provider),\n mcpPort: options.port ? Number(options.port) : undefined,\n withBrowser: true,\n withTools: false,\n });\n}\n\n/** Require a connected browser or exit with guidance. */\nfunction requireBrowserPage(engine: Awaited<ReturnType<typeof startEngine>>): Page {\n const browser = engine.browser;\n if (!browser) {\n void engine.shutdown({ closeBrowser: false });\n fail(\"Browser not connected. Run `bridge login` once to sign in to ChatGPT.\");\n }\n return browser.getPage();\n}\n\n// --- headless/workspace.ts ---\n\n/** Reject non-ChatGPT providers: Projects, chat moves, and Scheduled tasks are ChatGPT-only. */\nfunction assertChatgptWorkspace(options: CommonCliOptions): void {\n if (normalizeProvider(options.provider) !== \"chatgpt\") {\n fail(\n \"Projects, chat moves, and Scheduled tasks are ChatGPT-only. Omit --provider or pass --provider chatgpt.\",\n );\n }\n}\n\n/** Start a ChatGPT engine attached to the warm browser and resolve its page. */\nasync function startWorkspaceSession(options: CommonCliOptions) {\n const engine = await startEngine({\n repoPath: options.repo ? resolve(options.repo) : undefined,\n provider: \"chatgpt\",\n mcpPort: options.port ? Number(options.port) : undefined,\n withBrowser: true,\n withTools: false,\n });\n return { engine, page: requireBrowserPage(engine) };\n}\n\n/** `bridge project list` — print the ChatGPT Projects, one per line (or JSON). */\nasync function runProjectListCmd(options: ProjectCmdOptions): Promise<void> {\n assertChatgptWorkspace(options);\n redirectConsoleToStderr();\n const { engine, page } = await startWorkspaceSession(options);\n const projects = await listProjects(page);\n await engine.shutdown({ closeBrowser: false });\n if (options.json) process.stdout.write(`${JSON.stringify(projects)}\\n`);\n else if (projects.length === 0) process.stdout.write(\"No projects.\\n\");\n else for (const project of projects) process.stdout.write(`${project.name}\\n`);\n process.exit(0);\n}\n\n/** `bridge project create <name>` — create a ChatGPT Project. */\nasync function runProjectCreateCmd(name: string, options: ProjectCmdOptions): Promise<void> {\n assertChatgptWorkspace(options);\n if (!name.trim()) fail(\"Usage: bridge project create <name>\");\n redirectConsoleToStderr();\n const { engine, page } = await startWorkspaceSession(options);\n const project = await createProject(page, name);\n await engine.shutdown({ closeBrowser: false });\n if (options.json) process.stdout.write(`${JSON.stringify(project)}\\n`);\n else process.stdout.write(`Created project: ${project.name}\\n`);\n process.exit(0);\n}\n\n/** `bridge chat list [--orphans]` — list sidebar (project-less) conversations. */\nasync function runChatListCmd(options: ChatCmdOptions): Promise<void> {\n assertChatgptWorkspace(options);\n redirectConsoleToStderr();\n const { engine } = await startWorkspaceSession(options);\n const chats = await engine.getOrchestrator().listConversations();\n await engine.shutdown({ closeBrowser: false });\n if (options.json) process.stdout.write(`${JSON.stringify(chats)}\\n`);\n else if (chats.length === 0) process.stdout.write(\"No conversations.\\n\");\n else for (const chat of chats) process.stdout.write(`${chat.id}\\t${chat.title}\\n`);\n process.exit(0);\n}\n\n/** `bridge chat move <idOrTitle> --project <name>` — move one conversation into a Project. */\nasync function runChatMoveCmd(chat: string, options: ChatCmdOptions): Promise<void> {\n assertChatgptWorkspace(options);\n const project = options.project?.trim();\n if (!chat.trim() || !project) fail(\"Usage: bridge chat move <idOrTitle> --project <name>\");\n redirectConsoleToStderr();\n const { engine, page } = await startWorkspaceSession(options);\n const outcome = await moveChatToProject(page, { chat, project });\n await engine.shutdown({ closeBrowser: false });\n if (options.json) process.stdout.write(`${JSON.stringify(outcome)}\\n`);\n else if (outcome.moved) process.stdout.write(`Moved \"${outcome.chat}\" -> ${outcome.project}\\n`);\n else process.stdout.write(`Skipped \"${outcome.chat}\": ${outcome.reason}\\n`);\n process.exit(outcome.moved ? 0 : 1);\n}\n\n/** `bridge task list` — list ChatGPT Scheduled tasks. */\nasync function runTaskListCmd(options: TaskCmdOptions): Promise<void> {\n assertChatgptWorkspace(options);\n redirectConsoleToStderr();\n const { engine, page } = await startWorkspaceSession(options);\n const tasks = await listTasks(page);\n await engine.shutdown({ closeBrowser: false });\n if (options.json) process.stdout.write(`${JSON.stringify(tasks)}\\n`);\n else if (tasks.length === 0) process.stdout.write(\"No scheduled tasks.\\n\");\n else\n for (const task of tasks)\n process.stdout.write(`${task.title}${task.schedule ? `\\t${task.schedule}` : \"\"}\\n`);\n process.exit(0);\n}\n\n/** `bridge task create <prompt> [--every|--at]` — schedule a task via natural language. */\nasync function runTaskCreateCmd(prompt: string, options: TaskCmdOptions): Promise<void> {\n assertChatgptWorkspace(options);\n if (!prompt.trim()) fail(\"Usage: bridge task create <prompt> [--every <spec> | --at <spec>]\");\n redirectConsoleToStderr();\n const { engine } = await startWorkspaceSession(options);\n const content = buildTaskPrompt(prompt, options);\n const reply = await engine.ask({ content });\n await engine.shutdown({ closeBrowser: false });\n if (options.json)\n process.stdout.write(`${JSON.stringify({ content, reply: reply?.content ?? null })}\\n`);\n else process.stdout.write(`${reply?.content ?? \"(no reply captured)\"}\\n`);\n process.exit(0);\n}\n\n/** Compose the natural-language instruction ChatGPT turns into a Scheduled task. */\nexport function buildTaskPrompt(prompt: string, options: TaskCmdOptions): string {\n const cadence = options.every ? `every ${options.every}` : options.at ? `at ${options.at}` : \"\";\n const when = cadence ? ` Schedule it to run ${cadence}.` : \"\";\n return `Set up a ChatGPT scheduled task: ${prompt.trim()}.${when}`;\n}\n\n// --- headless/login.ts ---\n\n/** Options for the non-interactive `bridge login` command. */\n/**\n * Open the isolated Chrome profile so the user can sign in once.\n * The browser is left running (warm) for subsequent `bridge ask` calls.\n */\nasync function runLoginCmd(options: LoginOptions = {}): Promise<void> {\n const browser = await launchLoginBrowser(options);\n writeLoginInstructions(getBrowserProvider(normalizeProvider(options.provider)).displayName);\n process.exit(0);\n}\n\n/** Launch the isolated browser profile for sign-in. */\nasync function launchLoginBrowser(options: LoginOptions): Promise<BrowserManager> {\n const provider = normalizeProvider(options.provider);\n const browser = new BrowserManager(options.repo ? resolve(options.repo) : undefined, provider);\n await browser.launch();\n return browser;\n}\n\n/** Print sign-in instructions to stderr. */\nfunction writeLoginInstructions(displayName: string): void {\n process.stderr.write(\n `Bridge Chrome is open for ${displayName} (isolated profile — NOT your daily browser).\nIf you see a Sign in / Log in button, click it and sign in NOW in this window.\nYour main Chrome cookies do not carry over. Sign-in persists across runs.\nLeave this window open; \\`bridge ask\\` will reconnect to it.\n`,\n );\n}\n\n// --- headless/stop.ts ---\n\n/** Close the warm Chrome instance holding the debug port. */\nasync function runStopCmd(): Promise<void> {\n const killed = await killDebugPort(BRIDGE_DEBUG_PORT);\n process.stderr.write(\n killed ? \"Closed the bridge browser.\\n\" : \"No bridge browser was running.\\n\",\n );\n process.exit(0);\n}\n\n// --- run-tui.ts ---\n\n/** Launch the interactive Ink TUI on top of a shared engine. */\nasync function runTui(opts: CommonCliOptions & { browser?: boolean }): Promise<void> {\n if (!process.stdout.isTTY) {\n process.stderr.write(\n \"bridge: the interactive TUI needs a TTY. Use `bridge ask <prompt>` for non-interactive or piped use.\\n\",\n );\n process.exit(1);\n }\n const provider = normalizeProvider(opts.provider);\n const label = getProviderDisplayName(provider);\n console.log(`\\nStarting ai-browser-bridge (${label})...`);\n const engine = await startEngine({\n repoPath: opts.repo ? resolve(opts.repo) : undefined,\n provider,\n mcpPort: opts.port ? Number(opts.port) : undefined,\n withBrowser: opts.browser !== false,\n withTools: provider === \"chatgpt\",\n log: (line) => console.error(line),\n });\n await renderTui(engine);\n}\n\n/** Wire engine events into the Ink app and handle shutdown signals. */\nasync function renderTui(engine: Awaited<ReturnType<typeof startEngine>>): Promise<void> {\n const messages: Message[] = [];\n attachOrchestratorListener({ engine, messages });\n const shutdown = buildShutdownHandler(engine);\n registerShutdownSignals(shutdown);\n const app = renderBridgeApp({ engine, messages, shutdown });\n await app.waitUntilExit();\n}\n\n/** Mirror orchestrator message events into the TUI message list. */\nfunction attachOrchestratorListener(input: {\n engine: Awaited<ReturnType<typeof startEngine>>;\n messages: Message[];\n}): void {\n input.engine.getOrchestrator().on((event) => {\n if (event.type === \"message\") input.messages.push(event.message);\n if (event.type === \"conversation_synced\") {\n input.messages.length = 0;\n input.messages.push(...event.messages);\n }\n if (event.type === \"reset\") input.messages.length = 0;\n if (event.type === \"error\") {\n input.messages.push({\n id: crypto.randomUUID(),\n role: \"assistant\",\n content: `⚠ ${event.error}`,\n timestamp: Date.now(),\n });\n }\n });\n}\n\n/** Build a shutdown handler that aborts, tears down, and exits. */\nfunction buildShutdownHandler(engine: Awaited<ReturnType<typeof startEngine>>) {\n return async (code = 0): Promise<void> => {\n await engine\n .getOrchestrator()\n .stopResponse()\n .catch(() => {});\n await engine.shutdown({ closeBrowser: false });\n process.exit(code);\n };\n}\n\n/** Register SIGINT/SIGTERM handlers for graceful TUI shutdown. */\nfunction registerShutdownSignals(shutdown: (code?: number) => Promise<void>): void {\n process.once(\"SIGINT\", () => void shutdown(130));\n process.once(\"SIGTERM\", () => void shutdown(143));\n}\n\n/** Render the Ink BridgeApp with engine wiring. */\nfunction renderBridgeApp(input: {\n engine: Awaited<ReturnType<typeof startEngine>>;\n messages: Message[];\n shutdown: (code?: number) => Promise<void>;\n}): ReturnType<typeof render> {\n return render(\n React.createElement(BridgeApp, {\n config: input.engine.config,\n sendMessage: async (content: string) => {\n await input.engine.ask({ content });\n },\n clearMessages: () => {\n input.messages.length = 0;\n },\n shutdown: () => input.shutdown(0),\n messages: input.messages,\n counter: input.engine.counter,\n orchestrator: input.engine.getOrchestrator(),\n permission: {\n getMode: () => input.engine.permissionMode,\n setMode: (mode) => {\n input.engine.permissionMode = mode;\n },\n },\n session: {\n getId: () => input.engine.sessionId,\n setId: (id) => {\n input.engine.sessionId = id;\n },\n },\n statusline: {\n branch: input.engine.branch,\n toolCallCount: () => input.engine.toolActions.length,\n },\n }),\n );\n}\n\n/** Terminal CLI runner: interactive TUI and headless subcommands. */\nexport class CliRunner {\n /** Launch the interactive Ink TUI (default `bridge` action). */\n async runDefault(opts: CommonCliOptions & { browser?: boolean }): Promise<void> {\n await runTui(opts);\n }\n\n /** Send one prompt and print the reply (non-interactive `bridge ask`). */\n async runAsk(prompt: string, options: AskOptions): Promise<void> {\n await runAskFlow({ prompt, options: options ?? {} });\n }\n\n /** Open the bridge Chrome profile to sign in once. */\n async runLogin(options: LoginOptions = {}): Promise<void> {\n await runLoginCmd(options);\n }\n\n /** Close the warm bridge browser. */\n async runStop(): Promise<void> {\n await runStopCmd();\n }\n\n /** List stored bridge sessions as JSON. */\n async runSessions(): Promise<void> {\n await runSessionsCmd();\n }\n}\n\n// --- module re-exports for TUI, tests, register-cli ---\n\nexport type { AskOptions, DownloadCmdOptions, DownloadResult, LoginOptions };\n\n/** Send one prompt and print the reply, leaving the browser warm. */\nexport async function runAsk(prompt: string, options: AskOptions): Promise<void> {\n const runner = new CliRunner();\n await runner.runAsk(prompt, options);\n}\n\n/** Download a conversation's attachments to disk without the TUI. */\nexport async function runDownload(options: DownloadCmdOptions): Promise<void> {\n await runDownloadCmd(options);\n}\n\nexport { parseAttachmentIds, formatDownloadLine };\n\n/** `bridge project list` — list ChatGPT Projects (ChatGPT only). */\nexport async function runProjectList(options: ProjectCmdOptions): Promise<void> {\n await runProjectListCmd(options);\n}\n\n/** `bridge project create <name>` — create a ChatGPT Project (ChatGPT only). */\nexport async function runProjectCreate(name: string, options: ProjectCmdOptions): Promise<void> {\n await runProjectCreateCmd(name, options);\n}\n\n/** `bridge chat list` — list sidebar (project-less) conversations (ChatGPT only). */\nexport async function runChatList(options: ChatCmdOptions): Promise<void> {\n await runChatListCmd(options);\n}\n\n/** `bridge chat move <idOrTitle> --project <name>` — move a conversation into a Project. */\nexport async function runChatMove(chat: string, options: ChatCmdOptions): Promise<void> {\n await runChatMoveCmd(chat, options);\n}\n\n/** `bridge task list` — list ChatGPT Scheduled tasks (ChatGPT only). */\nexport async function runTaskList(options: TaskCmdOptions): Promise<void> {\n await runTaskListCmd(options);\n}\n\n/** `bridge task create <prompt> [--every|--at]` — schedule a task via natural language. */\nexport async function runTaskCreate(prompt: string, options: TaskCmdOptions): Promise<void> {\n await runTaskCreateCmd(prompt, options);\n}\n\n/** Open the isolated Chrome profile so the user can sign in once. */\nexport async function runLogin(options: LoginOptions = {}): Promise<void> {\n const runner = new CliRunner();\n await runner.runLogin(options);\n}\n\n/** Close the warm Chrome instance holding the debug port. */\nexport async function runStop(): Promise<void> {\n const runner = new CliRunner();\n await runner.runStop();\n}\n\nexport { abortAndExit, timeoutMsFromSeconds };\n\n/** Print stored bridge sessions (newest first) as JSON. */\nexport async function runSessions(): Promise<void> {\n const runner = new CliRunner();\n await runner.runSessions();\n}\n\nexport { executeCommand, getAllCommands, matchCommands, parseCommand, registerCommand };\n\nexport { buildProjectTaskPrompt, buildProjectTaskPromptWithInstructions };\n\nexport {\n formatSessionSummary,\n mcpConnectorUrl,\n formatBridgeStatus,\n formatMcpDiagnostics,\n formatConnectorSetupResult,\n};\n","import { mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { PROVIDER_CONFIG } from \"@/config\";\nimport type {\n Attachment,\n AttachmentManifest,\n AttachmentRole,\n ConnectorSetupOptions,\n ConnectorSetupResult,\n ModelOption,\n} from \"@/features/domain\";\nimport type { APIResponse, Locator, Page, Response } from \"playwright\";\nimport type { BrowserProvider } from \"../browserProviderTypes.ts\";\nimport { conversationUrlFromIdOrUrl, isSameChatGptConversation } from \"../conversationUrl.ts\";\nimport { GuestSessionError } from \"../guestSessionError.ts\";\n\n/** True when an unknown error is a Node.js ErrnoException with a code field. */\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return typeof error === \"object\" && error !== null && \"code\" in error;\n}\n\n// GuestSessionError is shared across providers; see ../guestSessionError.ts.\nexport { GuestSessionError };\n\n// --- actions/attach-files-to-prompt.ts ---\n\n/** Attach local files to the ChatGPT composer when the browser UI exposes file upload. */\nasync function attachFilesToPrompt(page: Page, paths: string[]): Promise<void> {\n if (paths.length === 0) return;\n if (await attachFilesViaInput({ page, paths })) return;\n await attachFilesViaChooser({ page, paths });\n}\n\n// --- actions/attach-files-via-chooser.ts ---\n\n/** Context for {@link openAttachmentFileChooser}. */\ninterface OpenAttachmentFileChooserContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Open the attachment file chooser via the composer attach button. */\nasync function openAttachmentFileChooser(ctx: OpenAttachmentFileChooserContext) {\n const attachButton = await firstVisible({\n page: ctx.page,\n selectors: [\n 'button[aria-label*=\"Attach\" i]',\n 'button[aria-label*=\"Upload\" i]',\n 'button[data-testid*=\"attach\" i]',\n 'button[data-testid*=\"upload\" i]',\n ],\n });\n if (!attachButton) throw new Error(\"Could not find ChatGPT attachment control.\");\n const chooserPromise = ctx.page.waitForEvent(\"filechooser\", { timeout: 5_000 });\n await attachButton.click();\n return chooserPromise;\n}\n\n/** Context for {@link attachFilesViaChooser}. */\ninterface AttachFilesViaChooserContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Local file paths to attach. */\n paths: string[];\n}\n\n/** Attach files by clicking the attachment button and using the file chooser. */\nasync function attachFilesViaChooser(ctx: AttachFilesViaChooserContext): Promise<void> {\n const chooser = await openAttachmentFileChooser({ page: ctx.page });\n await (await chooser).setFiles(ctx.paths);\n}\n\n// --- actions/attach-files-via-input.ts ---\n\n/** Context for {@link attachFilesViaInput}. */\ninterface AttachFilesViaInputContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Local file paths to attach. */\n paths: string[];\n}\n\n/** Attach files through a visible file input when one exists. */\nasync function attachFilesViaInput(ctx: AttachFilesViaInputContext): Promise<boolean> {\n const input = ctx.page.locator(SELECTORS.attachmentInput).first();\n if ((await input.count()) === 0) return false;\n await input.setInputFiles(ctx.paths);\n return true;\n}\n\n// --- actions/build-prepared-rewind-turn.ts ---\n\n/** Context for {@link buildPreparedRewindTurn}. */\ninterface BuildPreparedRewindTurnContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: PrepareRewindTurnContext[\"page\"];\n /** Optional replacement text for the last user message. */\n replacement?: string;\n /** Last user message block locator. */\n lastUserBlock: Locator;\n /** Assistant block count before rewind. */\n previousAssistantCount: number;\n /** Last assistant text before rewind. */\n previousLastAssistantText: string;\n}\n\n/** Build prepared rewind state from loaded baseline values. */\nasync function buildPreparedRewindTurn(\n ctx: BuildPreparedRewindTurnContext,\n): Promise<PreparedRewindTurn> {\n const turnScope = await resolveLastUserTurnScope({ lastUserBlock: ctx.lastUserBlock });\n const prompt = resolveRewindPrompt({\n replacement: ctx.replacement,\n previousText: await readLastUserPromptText({ lastUserBlock: ctx.lastUserBlock }),\n });\n return {\n page: ctx.page,\n turnScope,\n prompt,\n previousAssistantCount: ctx.previousAssistantCount,\n previousLastAssistantText: ctx.previousLastAssistantText,\n };\n}\n\n// --- actions/load-last-user-block.ts ---\n\n/** Context for {@link loadLastUserBlock}. */\ninterface LoadLastUserBlockContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: import(\"playwright\").Page;\n}\n\n/** Load the last user message block or throw when none exist. */\nasync function loadLastUserBlock(ctx: LoadLastUserBlockContext) {\n const blocks = await ctx.page.locator(SELECTORS.userBlock).all();\n const last = blocks[blocks.length - 1];\n if (last === undefined) throw new Error(\"No user message found to rewind.\");\n return last;\n}\n\n// --- actions/open-rewind-editor.ts ---\n\n/** Context for {@link clickRewindEditButton}. */\ninterface ClickRewindEditButtonContext {\n /** Prepared rewind turn state. */\n prepared: PreparedRewindTurn;\n}\n\n/** Hover the turn and click its edit button. */\nasync function clickRewindEditButton(ctx: ClickRewindEditButtonContext): Promise<void> {\n await ctx.prepared.turnScope.hover().catch(() => {});\n await ctx.prepared.page.waitForTimeout(300);\n const editButton = await findRewindEditButton({ turnScope: ctx.prepared.turnScope });\n if (!editButton) throw new Error(\"Could not find ChatGPT edit button for the last user message.\");\n await editButton.click();\n}\n\n/** Context for {@link openRewindEditor}. */\ninterface OpenRewindEditorContext {\n /** Prepared rewind turn state. */\n prepared: PreparedRewindTurn;\n}\n\n/** Hover the turn, click edit, and locate the editable prompt field. */\nasync function openRewindEditor(ctx: OpenRewindEditorContext) {\n await clickRewindEditButton({ prepared: ctx.prepared });\n return findRewindEditor({ page: ctx.prepared.page, turnScope: ctx.prepared.turnScope });\n}\n\n// --- actions/prepare-rewind-turn.ts ---\n\n/** Load the last user block and baseline counts for a rewind operation. */\nasync function prepareRewindTurn(ctx: PrepareRewindTurnContext): Promise<PreparedRewindTurn> {\n const lastUserBlock = await loadLastUserBlock({ page: ctx.page });\n const previousAssistantCount = await countAssistantResponses(ctx.page);\n const previousLastAssistantText = await captureLastResponse(ctx.page);\n return buildPreparedRewindTurn({\n page: ctx.page,\n replacement: ctx.replacement,\n lastUserBlock,\n previousAssistantCount,\n previousLastAssistantText,\n });\n}\n\n// --- actions/rewind-controls.ts ---\n\n/** Context for {@link findRewindEditButton}. */\ninterface FindRewindEditButtonContext {\n /** Conversation turn scope locator. */\n turnScope: Locator;\n}\n\n/** Find the edit button for the last user message within a turn scope. */\nasync function findRewindEditButton(ctx: FindRewindEditButtonContext) {\n return firstVisibleIn({ parent: ctx.turnScope, selectors: EDIT_BUTTON_SELECTORS });\n}\n\n/** Context for {@link findRewindEditor}. */\ninterface FindRewindEditorContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Conversation turn scope locator. */\n turnScope: Locator;\n}\n\n/** Find the editable prompt field after clicking edit. */\nasync function findRewindEditor(ctx: FindRewindEditorContext) {\n return (\n firstVisibleIn({ parent: ctx.turnScope, selectors: EDITOR_SELECTORS }) ??\n firstVisible({ page: ctx.page, selectors: EDITOR_SELECTORS })\n );\n}\n\n/** Context for {@link findRewindSubmitButton}. */\ninterface FindRewindSubmitButtonContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Conversation turn scope locator. */\n turnScope: Locator;\n}\n\n/** Find the submit button for an edited prompt. */\nasync function findRewindSubmitButton(ctx: FindRewindSubmitButtonContext) {\n return (\n firstVisibleIn({ parent: ctx.turnScope, selectors: SUBMIT_BUTTON_SELECTORS }) ??\n firstVisible({ page: ctx.page, selectors: SUBMIT_BUTTON_SELECTORS })\n );\n}\n\n/** Context for {@link submitRewindEditor}. */\ninterface SubmitRewindEditorContext {\n /** Editable prompt field locator. */\n editor: Locator;\n /** Prompt text to write before submitting. */\n prompt: string;\n}\n\n/** Fill the rewind editor with the replacement prompt. */\nasync function submitRewindEditor(ctx: SubmitRewindEditorContext): Promise<void> {\n await ctx.editor.click();\n await ctx.editor.fill(ctx.prompt);\n await ctx.editor.dispatchEvent(\"input\").catch(() => {});\n}\n\n// --- actions/rewind-helpers.ts ---\n\n/** Context for {@link resolveLastUserTurnScope}. */\ninterface ResolveLastUserTurnScopeContext {\n /** Last user message block locator. */\n lastUserBlock: Locator;\n}\n\n/** Resolve the conversation turn scope for hovering edit controls. */\nasync function resolveLastUserTurnScope(ctx: ResolveLastUserTurnScopeContext): Promise<Locator> {\n const turn = ctx.lastUserBlock.locator(\n 'xpath=ancestor::section[starts-with(@data-testid, \"conversation-turn-\")][1]',\n );\n return (await turn.count()) > 0 ? turn : ctx.lastUserBlock;\n}\n\n/** Edit-button selectors scoped to a user turn. */\nconst EDIT_BUTTON_SELECTORS = [\n 'button[data-testid=\"edit-turn-button\"]',\n 'button[data-testid=\"edit-message-button\"]',\n 'button[aria-label=\"Edit message\"]',\n 'button[aria-label*=\"Edit\" i]',\n 'button[title=\"Edit message\"]',\n 'button:has-text(\"Edit\")',\n] as const;\n\n/** Editor selectors scoped to a user turn or page. */\nconst EDITOR_SELECTORS = [\n 'textarea[name=\"prompt-textarea\"]',\n '[contenteditable=\"true\"][role=\"textbox\"]',\n '[contenteditable=\"true\"]',\n \"textarea\",\n] as const;\n\n/** Submit-button selectors for edited prompts. */\nconst SUBMIT_BUTTON_SELECTORS = [\n 'button[data-testid=\"send-button\"]',\n 'button[aria-label=\"Submit\"]',\n 'button[aria-label=\"Send\"]',\n 'button[aria-label=\"Send prompt\"]',\n 'button:has-text(\"Save & submit\")',\n 'button:has-text(\"Submit\")',\n 'button:has-text(\"Update\")',\n] as const;\n\n/** Context for {@link readLastUserPromptText}. */\ninterface ReadLastUserPromptTextContext {\n /** Last user message block locator. */\n lastUserBlock: Locator;\n}\n\n/** Read normalized text from the last user message block. */\nasync function readLastUserPromptText(ctx: ReadLastUserPromptTextContext): Promise<string> {\n return normalizeDisplayText({ value: await ctx.lastUserBlock.innerText() });\n}\n\n/** Context for {@link resolveRewindPrompt}. */\ninterface ResolveRewindPromptContext {\n /** Optional replacement prompt text. */\n replacement?: string;\n /** Previous text from the last user message. */\n previousText: string;\n}\n\n/** Resolve the prompt text to submit when rewinding the last user message. */\nfunction resolveRewindPrompt(ctx: ResolveRewindPromptContext): string {\n const prompt = ctx.replacement?.trim() || ctx.previousText;\n if (!prompt) throw new Error(\"Last user message is empty.\");\n return prompt;\n}\n\n// --- actions/rewind-last-user-prompt.ts ---\n\n/** Edit the last user message and submit it again, optionally replacing its content. */\nasync function rewindLastUserPrompt(page: Page, replacement?: string): Promise<void> {\n const prepared = await prepareRewindTurn({ page, replacement });\n await submitRewindTurn({ prepared });\n}\n\n// --- actions/rewind.types.ts ---\n\n/** Prepared rewind turn state before editing and submitting. */\ninterface PreparedRewindTurn {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Conversation turn scope locator. */\n turnScope: Locator;\n /** Prompt text to submit. */\n prompt: string;\n /** Assistant block count before rewind. */\n previousAssistantCount: number;\n /** Last assistant text before rewind. */\n previousLastAssistantText: string;\n}\n\n/** Context for {@link prepareRewindTurn}. */\ninterface PrepareRewindTurnContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Optional replacement text for the last user message. */\n replacement?: string;\n}\n\n// --- actions/stop-generating.ts ---\n\n/** Stop the active streaming response when ChatGPT exposes the stop button. */\nasync function stopGenerating(page: Page, timeout = 5_000): Promise<boolean> {\n const stop = page.locator(SELECTORS.streamingIndicator).first();\n try {\n await stop.waitFor({ state: \"visible\", timeout });\n } catch {\n return false;\n }\n await stop.click();\n return true;\n}\n\n// --- actions/submit-edited-rewind-turn.ts ---\n\n/** Context for {@link submitEditedRewindTurn}. */\ninterface SubmitEditedRewindTurnContext {\n /** Prepared rewind turn state. */\n prepared: PreparedRewindTurn;\n}\n\n/** Submit the edited rewind turn and wait for the new response. */\nasync function submitEditedRewindTurn(ctx: SubmitEditedRewindTurnContext): Promise<void> {\n const submitButton = await findRewindSubmitButton({\n page: ctx.prepared.page,\n turnScope: ctx.prepared.turnScope,\n });\n if (!submitButton) throw new Error(\"Could not find submit button for edited prompt.\");\n await submitButton.click();\n await waitForResponse(ctx.prepared.page, {\n previousAssistantCount: ctx.prepared.previousAssistantCount,\n previousLastAssistantText: ctx.prepared.previousLastAssistantText,\n });\n}\n\n// --- actions/submit-rewind-turn.ts ---\n\n/** Context for {@link submitRewindTurn}. */\ninterface SubmitRewindTurnContext {\n /** Prepared rewind turn state. */\n prepared: PreparedRewindTurn;\n}\n\n/** Hover, edit, and resubmit the last user turn. */\nasync function submitRewindTurn(ctx: SubmitRewindTurnContext): Promise<void> {\n const editor = await openRewindEditor({ prepared: ctx.prepared });\n if (!editor) throw new Error(\"Could not find editable prompt field after clicking edit.\");\n await submitRewindEditor({ editor, prompt: ctx.prepared.prompt });\n await submitEditedRewindTurn({ prepared: ctx.prepared });\n}\n\n// --- attachments/assign-attachments-resolve.ts ---\n\n/** Resolve one attachment candidate to a stable id, reusing existing records when possible. */\nfunction resolveAttachment(ctx: {\n item: ExtractedContent[\"attachments\"][number];\n params: {\n role: AttachmentRole;\n messageIndex: number;\n counters: AttachmentCounters;\n createdAt: string;\n existing: Attachment[];\n };\n usedExistingIds: Set<string>;\n newAttachments: Attachment[];\n}): Attachment {\n const existing = findExistingAttachment(ctx);\n if (existing) return reuseExisting({ ctx, existing });\n return createAttachment(ctx);\n}\n\nfunction reuseExisting(params: {\n ctx: { usedExistingIds: Set<string> };\n existing: Attachment;\n}): Attachment {\n params.ctx.usedExistingIds.add(params.existing.id);\n return params.existing;\n}\n\nfunction createAttachment(ctx: {\n item: ExtractedContent[\"attachments\"][number];\n params: {\n role: AttachmentRole;\n messageIndex: number;\n counters: AttachmentCounters;\n createdAt: string;\n };\n newAttachments: Attachment[];\n}): Attachment {\n ctx.params.counters[ctx.params.role][ctx.item.kind] += 1;\n const attachment = buildAttachment(ctx);\n ctx.newAttachments.push(attachment);\n return attachment;\n}\n\nfunction findExistingAttachment(ctx: {\n item: ExtractedContent[\"attachments\"][number];\n params: { role: AttachmentRole; messageIndex: number; existing: Attachment[] };\n usedExistingIds: Set<string>;\n}): Attachment | undefined {\n return ctx.params.existing.find(\n (attachment) =>\n !ctx.usedExistingIds.has(attachment.id) &&\n attachment.role === ctx.params.role &&\n attachment.messageIndex === ctx.params.messageIndex &&\n attachment.kind === ctx.item.kind &&\n attachment.url === ctx.item.url,\n );\n}\n\nfunction buildAttachment(ctx: {\n item: ExtractedContent[\"attachments\"][number];\n params: {\n role: AttachmentRole;\n messageIndex: number;\n counters: AttachmentCounters;\n createdAt: string;\n };\n}): Attachment {\n const suffix = ctx.params.counters[ctx.params.role][ctx.item.kind];\n return {\n ...ctx.item,\n id: attachmentId({ role: ctx.params.role, kind: ctx.item.kind, suffix }),\n role: ctx.params.role,\n messageIndex: ctx.params.messageIndex,\n createdAt: ctx.params.createdAt,\n };\n}\n\nfunction attachmentId(params: {\n role: AttachmentRole;\n kind: AttachmentKind;\n suffix: number;\n}): string {\n return params.role === \"user\"\n ? `user-${params.kind}-${params.suffix}`\n : `${params.kind}-${params.suffix}`;\n}\n\n// --- attachments/assign-attachments.ts ---\n\n/** Register extracted assistant content and persist new attachment ids. */\nasync function registerExtractedContent(params: {\n conversationId: string;\n messageIndex: number;\n extracted: ExtractedContent;\n}): Promise<{ text: string; attachments: Attachment[] }> {\n const manifest = await loadManifest(params.conversationId);\n const registered = assignAttachmentIds({\n extracted: params.extracted,\n role: \"assistant\",\n messageIndex: params.messageIndex,\n counters: countersFromManifest(manifest),\n createdAt: new Date().toISOString(),\n existing: manifest.attachments,\n });\n return finalizeRegistration({ manifest, registered });\n}\n\n/** Assign stable attachment ids and replace temporary markers in text. */\nfunction assignAttachmentIds(params: {\n extracted: ExtractedContent;\n role: AttachmentRole;\n messageIndex: number;\n counters: AttachmentCounters;\n createdAt: string;\n existing: Attachment[];\n}): {\n text: string;\n attachments: Attachment[];\n newAttachments: Attachment[];\n counters: AttachmentCounters;\n} {\n const usedExistingIds = new Set<string>();\n const newAttachments: Attachment[] = [];\n const attachments = params.extracted.attachments.map((item) =>\n resolveAttachment({ item, params, usedExistingIds, newAttachments }),\n );\n return {\n text: replaceMarkers({ text: params.extracted.text, attachments }),\n attachments,\n newAttachments,\n counters: params.counters,\n };\n}\n\nasync function finalizeRegistration(params: {\n manifest: Awaited<ReturnType<typeof loadManifest>>;\n registered: ReturnType<typeof assignAttachmentIds>;\n}): Promise<{ text: string; attachments: Attachment[] }> {\n params.manifest.attachments.push(...params.registered.newAttachments);\n params.manifest.counters = params.registered.counters;\n await saveManifest(params.manifest);\n return { text: params.registered.text, attachments: params.registered.attachments };\n}\n\nfunction replaceMarkers(params: { text: string; attachments: Attachment[] }): string {\n let content = params.text;\n for (let index = 0; index < params.attachments.length; index += 1) {\n content = content.replace(markerFor(index), `[${params.attachments[index]?.id ?? \"\"}]`);\n }\n return content;\n}\n\nfunction markerFor(index: number): string {\n return `${MARKER_PREFIX}${index}${MARKER_SUFFIX}`;\n}\n\n// --- attachments/attachment-types.ts ---\n\n/** Minimal DOM snapshot used by the attachment walker. */\nexport type DomSnapshotNode =\n | { type: \"text\"; text: string }\n | {\n type: \"element\";\n tagName: string;\n attributes: Record<string, string>;\n children: DomSnapshotNode[];\n };\n\n/** Attachment kind inferred from a DOM element. */\ntype AttachmentKind = Attachment[\"kind\"];\n\n/** Per-role attachment id counters stored in the manifest. */\ntype AttachmentCounters = Record<AttachmentRole, Record<AttachmentKind, number>>;\n\n/** Legacy flat counter shape accepted when normalizing manifests. */\ntype LegacyAttachmentCounters = Partial<Record<AttachmentKind, number>>;\n\n/** Options for extracting all conversation messages with attachments. */\ntype ExtractMessagesOptions = { conversationId: string; includeUserAttachments?: boolean };\n\n/** Attachment record shape before role normalization. */\ntype SerializedAttachment = Omit<Attachment, \"role\"> & { role?: AttachmentRole };\n\n/** Candidate attachment discovered while walking a DOM snapshot. */\ninterface AttachmentCandidate {\n kind: AttachmentKind;\n url: string;\n filename?: string;\n mime?: string;\n}\n\n/** Text and attachment candidates extracted from one message snapshot. */\ninterface ExtractedContent {\n text: string;\n attachments: AttachmentCandidate[];\n}\n\n/** Serialized conversation message produced by the in-page snapshot script. */\ninterface SerializedMessage {\n role: string;\n messageIndex: number;\n text: string;\n root: DomSnapshotNode;\n}\n\n/** Marker prefix used while walking snapshots before ids are assigned. */\nconst MARKER_PREFIX = \"\\u0000attachment:\";\n\n/** Marker suffix used while walking snapshots before ids are assigned. */\nconst MARKER_SUFFIX = \"\\u0000\";\n\n// --- attachments/dom-snapshot.dom-snippet.ts ---\nconst DOM_SNAPSHOT_HELPERS_SOURCE = String.raw`\nconst GENERATED_IMAGE_SELECTOR = 'img[src*=\"/backend-api/estuary/content\"], img[alt^=\"Generated image\"]';\n\nfunction serializeMessage(element, messageIndex) {\n return {\n role: element.getAttribute(\"data-message-author-role\") ?? \"unknown\",\n messageIndex,\n text: element instanceof HTMLElement ? element.innerText : element.textContent ?? \"\",\n root: snapshotNode(element),\n };\n}\n\n// Serialize one conversation turn. Resolves role from an inner role block when present;\n// otherwise a turn that only holds a generated image is treated as an assistant message.\n// Generated images that render outside the role block (but inside the turn) are appended\n// as extra children so the walker still visits them.\nfunction serializeTurn(turn, messageIndex) {\n const roleBlock = turn.querySelector(\"[data-message-author-role]\");\n const generatedImages = Array.from(turn.querySelectorAll(GENERATED_IMAGE_SELECTOR));\n\n if (!roleBlock) {\n if (generatedImages.length === 0) return null;\n return {\n role: \"assistant\",\n messageIndex,\n text: turn instanceof HTMLElement ? turn.innerText : turn.textContent ?? \"\",\n root: { type: \"element\", tagName: \"div\", attributes: {}, children: generatedImages.map(snapshotNode) },\n };\n }\n\n const message = serializeMessage(roleBlock, messageIndex);\n const outsideBlock = generatedImages.filter((image) => !roleBlock.contains(image));\n if (outsideBlock.length > 0) {\n message.root.children.push(...outsideBlock.map(snapshotNode));\n }\n return message;\n}\n\nfunction turnRole(turn) {\n const roleBlock = turn.querySelector(\"[data-message-author-role]\");\n if (roleBlock) return roleBlock.getAttribute(\"data-message-author-role\") ?? \"unknown\";\n if (turn.querySelector(GENERATED_IMAGE_SELECTOR)) return \"assistant\";\n return null;\n}\n\nfunction snapshotNode(node) {\n if (node.nodeType === Node.TEXT_NODE) {\n return { type: \"text\", text: node.textContent ?? \"\" };\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return { type: \"text\", text: \"\" };\n }\n\n const element = node;\n const attributes = {};\n for (const attribute of Array.from(element.attributes)) {\n attributes[attribute.name] = attribute.value;\n }\n if (element instanceof HTMLImageElement && element.currentSrc) {\n attributes.currentSrc = element.currentSrc;\n }\n\n return {\n type: \"element\",\n tagName: element.tagName.toLowerCase(),\n attributes,\n children: Array.from(element.childNodes).map(snapshotNode),\n };\n}\n`;\n\nconst LAST_ASSISTANT_MESSAGE_SNAPSHOT_SOURCE = String.raw`\n(() => {\n ${DOM_SNAPSHOT_HELPERS_SOURCE}\n\n const turns = Array.from(document.querySelectorAll('section[data-testid^=\"conversation-turn-\"]'));\n let assistantIndex = -1;\n let lastAssistant = null;\n for (const turn of turns) {\n if (turnRole(turn) === \"assistant\") {\n assistantIndex += 1;\n lastAssistant = serializeTurn(turn, assistantIndex);\n }\n }\n return lastAssistant;\n})()\n`;\n\nconst LAST_ASSISTANT_TURN_STATE_SOURCE = String.raw`\n(() => {\n ${DOM_SNAPSHOT_HELPERS_SOURCE}\n\n function countImageMarkers(text) {\n const matches = text.match(/\\[image-\\d+\\]/g);\n return matches ? matches.length : 0;\n }\n\n const turns = Array.from(document.querySelectorAll('section[data-testid^=\"conversation-turn-\"]'));\n let lastAssistantTurn = null;\n for (const turn of turns) {\n if (turnRole(turn) === \"assistant\") lastAssistantTurn = turn;\n }\n if (!lastAssistantTurn) {\n return { text: \"\", assetCount: 0, loadedAssetCount: 0, pendingAssetCount: 0, expectedImageMarkerCount: 0 };\n }\n\n const images = Array.from(lastAssistantTurn.querySelectorAll(GENERATED_IMAGE_SELECTOR));\n let loadedAssetCount = 0;\n let pendingAssetCount = 0;\n for (const node of images) {\n if (node instanceof HTMLImageElement) {\n if (node.complete && node.naturalWidth > 0) loadedAssetCount += 1;\n else pendingAssetCount += 1;\n } else {\n pendingAssetCount += 1;\n }\n }\n\n const roleBlock = lastAssistantTurn.querySelector('[data-message-author-role=\"assistant\"]');\n const rawText = roleBlock instanceof HTMLElement\n ? roleBlock.innerText\n : lastAssistantTurn.innerText ?? \"\";\n const text = rawText.replace(/\\s+/g, \" \").trim();\n\n return {\n text,\n assetCount: images.length,\n loadedAssetCount,\n pendingAssetCount,\n expectedImageMarkerCount: countImageMarkers(text),\n };\n})()\n`;\n\nconst ALL_MESSAGES_SNAPSHOT_SOURCE = String.raw`\n(() => {\n ${DOM_SNAPSHOT_HELPERS_SOURCE}\n\n let assistantIndex = -1;\n let userIndex = -1;\n const messages = [];\n for (const turn of Array.from(document.querySelectorAll('section[data-testid^=\"conversation-turn-\"]'))) {\n const role = turnRole(turn);\n if (role === null) continue;\n if (role === \"assistant\") assistantIndex += 1;\n if (role === \"user\") userIndex += 1;\n const message = serializeTurn(turn, role === \"assistant\" ? assistantIndex : role === \"user\" ? userIndex : -1);\n if (message) messages.push(message);\n }\n return messages;\n})()\n`;\n\n// --- attachments/download-attachment.ts ---\n\n/** Download one attachment from a conversation manifest. */\nasync function downloadAttachment(\n page: Page,\n conversationId: string,\n id: string,\n opts: DownloadOptions = {},\n): Promise<DownloadResult> {\n const manifest = await loadManifest(conversationId);\n const attachment = manifest.attachments.find((item: Attachment) => item.id === id);\n if (!attachment)\n throw new AttachmentDownloadError(id, undefined, `Attachment not found in manifest: ${id}`);\n return downloadResolvedAttachment({\n page,\n conversationId,\n attachment,\n attachments: manifest.attachments,\n opts,\n });\n}\n\n/** Download all or selected attachments sequentially. */\nasync function downloadAll(\n page: Page,\n conversationId: string,\n opts: DownloadAllOptions = {},\n): Promise<DownloadAllResult[]> {\n const manifest = await loadManifest(conversationId);\n const ids = opts.ids ?? manifest.attachments.map((attachment: Attachment) => attachment.id);\n const results = await downloadIds({ page, conversationId, ids, opts });\n if (results.length > 0 && results.every((result) => result.error)) {\n throw new AttachmentDownloadError(\n opts.ids?.join(\",\") ?? \"*\",\n undefined,\n `Failed to download all attachments for conversation ${conversationId}`,\n results,\n );\n }\n return results;\n}\n\ninterface DownloadResolvedInput {\n page: Page;\n conversationId: string;\n attachment: Attachment;\n attachments: Attachment[];\n opts: DownloadOptions;\n}\n\nasync function downloadResolvedAttachment(input: DownloadResolvedInput): Promise<DownloadResult> {\n const outDir = outputDirectory({\n conversationId: input.conversationId,\n outDir: input.opts.outDir,\n repoRoot: input.opts.repoRoot,\n });\n await mkdir(outDir, { recursive: true });\n try {\n if (isHttpUrl(input.attachment.url)) {\n return await downloadHttpAttachment({\n page: input.page,\n attachment: input.attachment,\n outDir,\n attachments: input.attachments,\n });\n }\n const filePath = await resolveDownloadPath({\n outDir,\n attachment: input.attachment,\n attachments: input.attachments,\n });\n const bytes = input.attachment.url.startsWith(\"blob:\")\n ? await fetchBlobBytes({ page: input.page, attachment: input.attachment })\n : parseDataUrl({ attachment: input.attachment });\n return await writeIfChanged({ filePath, bytes });\n } catch (error) {\n if (error instanceof AttachmentDownloadError) throw error;\n throw new AttachmentDownloadError(\n input.attachment.id,\n input.attachment.url,\n `Failed to download attachment ${input.attachment.id}`,\n error,\n );\n }\n}\n\ninterface DownloadIdsInput {\n page: Page;\n conversationId: string;\n ids: string[];\n opts: DownloadAllOptions;\n}\n\nasync function downloadIds(input: DownloadIdsInput): Promise<DownloadAllResult[]> {\n const results: DownloadAllResult[] = [];\n for (const attachmentId of input.ids) results.push(await downloadOneId({ input, attachmentId }));\n return results;\n}\n\nasync function downloadOneId(input: {\n input: DownloadIdsInput;\n attachmentId: string;\n}): Promise<DownloadAllResult> {\n try {\n const result = await downloadAttachment(\n input.input.page,\n input.input.conversationId,\n input.attachmentId,\n input.input.opts,\n );\n return { id: input.attachmentId, ...result };\n } catch (error) {\n return {\n id: input.attachmentId,\n path: \"\",\n bytes: 0,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n// --- attachments/download-attachmentTypes.ts ---\n/** Error raised when an attachment cannot be resolved or downloaded. */\nclass AttachmentDownloadError extends Error {\n /** Attachment id that failed to download. */\n readonly id: string;\n /** Source URL when known. */\n readonly url: string | undefined;\n override readonly cause: unknown;\n\n constructor(id: string, url: string | undefined, message: string, cause?: unknown) {\n super(message);\n this.name = \"AttachmentDownloadError\";\n this.id = id;\n this.url = url;\n this.cause = cause;\n }\n}\n\n/** Result of downloading a single attachment. */\ninterface DownloadResult {\n /** Absolute path to the saved file. */\n path: string;\n /** Number of bytes written or skipped. */\n bytes: number;\n}\n\n/** Per-item result when downloading multiple attachments. */\ninterface DownloadAllResult extends DownloadResult {\n /** Attachment id from the manifest. */\n id: string;\n /** Error message when the download failed. */\n error?: string;\n}\n\n/** Options for downloading one attachment. */\ninterface DownloadOptions {\n /** Optional output directory override. */\n outDir?: string;\n /** Repo root whose `.bridge/downloads` holds the default output directory. */\n repoRoot?: string;\n}\n\n/** Options for downloading many attachments. */\ninterface DownloadAllOptions extends DownloadOptions {\n /** Optional subset of attachment ids to download. */\n ids?: string[];\n}\n\n// --- attachments/download-filename.core.ts ---\n\ninterface ParseDataUrlInput {\n /** Attachment whose url is a data: URI. */\n attachment: Attachment;\n}\n\n/** Decode a data: URL attachment into bytes. */\nfunction parseDataUrl(input: ParseDataUrlInput): Buffer {\n const match = /^data:([^,]*),(.*)$/s.exec(input.attachment.url);\n if (!match) {\n throw new AttachmentDownloadError(\n input.attachment.id,\n input.attachment.url,\n `Invalid data URL for attachment ${input.attachment.id}`,\n );\n }\n return decodeDataUrlPayload({ metadata: match[1] ?? \"\", payload: match[2] ?? \"\" });\n}\n\nfunction decodeDataUrlPayload(input: { metadata: string; payload: string }): Buffer {\n if (input.metadata.split(\";\").includes(\"base64\")) return Buffer.from(input.payload, \"base64\");\n return Buffer.from(decodeURIComponent(input.payload), \"utf8\");\n}\n\ninterface SanitizeFilenameInput {\n /** Raw filename candidate. */\n value: string | undefined;\n}\n\n// biome-ignore lint/suspicious/noControlCharactersInRegex: intentionally strips control characters from filename candidates\nconst UNSAFE_FILENAME_CHARS = /[\\\\/\\0-\\x1f\\x7f]/g;\n\n/** Remove unsafe characters from a filename candidate. */\nfunction sanitizeFilename(input: SanitizeFilenameInput): string | undefined {\n const sanitized = input.value?.replace(UNSAFE_FILENAME_CHARS, \"\").replace(/^\\.+/, \"\").trim();\n return sanitized ? sanitized : undefined;\n}\n\ninterface FilenameFromUrlInput {\n /** URL whose pathname basename becomes the filename. */\n url: string;\n}\n\n/** Extract a filename from a URL pathname. */\nfunction filenameFromUrl(input: FilenameFromUrlInput): string | undefined {\n try {\n const parsed = new URL(input.url);\n const basename = path.posix.basename(parsed.pathname);\n return basename && basename !== \"/\" ? decodeURIComponent(basename) : undefined;\n } catch {\n return undefined;\n }\n}\n\ninterface SameAttachmentInput {\n /** First attachment to compare. */\n left: Attachment;\n /** Second attachment to compare. */\n right: Attachment;\n}\n\n/** Whether two attachments refer to the same artifact. */\nfunction isSameAttachment(input: SameAttachmentInput): boolean {\n return (\n input.left.id === input.right.id &&\n input.left.url === input.right.url &&\n input.left.filename === input.right.filename\n );\n}\n\n// --- attachments/download-filename.helpers.ts ---\n\nconst MIME_EXTENSIONS: Record<string, string> = {\n \"application/pdf\": \".pdf\",\n \"image/png\": \".png\",\n \"image/jpeg\": \".jpg\",\n \"image/webp\": \".webp\",\n \"image/gif\": \".gif\",\n};\n\ninterface ExtensionForMimeInput {\n /** MIME type used to infer a file extension. */\n mime: string | undefined;\n}\n\n/** Map a MIME type to a file extension when known. */\nfunction extensionForMime(input: ExtensionForMimeInput): string | undefined {\n const normalized = input.mime?.toLowerCase().split(\";\")[0]?.trim();\n return normalized ? MIME_EXTENSIONS[normalized] : undefined;\n}\n\ninterface ExtensionForAttachmentInput {\n /** Attachment whose kind and mime infer the extension. */\n attachment: Attachment;\n /** Optional MIME override from response headers. */\n mimeOverride?: string;\n}\n\n/** Infer a file extension for an attachment. */\nfunction extensionForAttachment(input: ExtensionForAttachmentInput): string {\n const mimeExtension =\n extensionForMime({ mime: input.mimeOverride }) ??\n extensionForMime({ mime: input.attachment.mime });\n if (mimeExtension) return mimeExtension;\n if (input.attachment.kind === \"image\") return \".png\";\n if (input.attachment.kind === \"pdf\") return \".pdf\";\n return \"\";\n}\n\ninterface WithMissingExtensionInput {\n filename: string;\n attachment: Attachment;\n mimeOverride?: string;\n}\n\n/** Append an inferred extension when the filename has none. */\nfunction withMissingExtension(input: WithMissingExtensionInput): string {\n if (path.extname(input.filename)) return input.filename;\n return `${input.filename}${extensionForAttachment({ attachment: input.attachment, mimeOverride: input.mimeOverride })}`;\n}\n\ninterface FilenameForAttachmentInput {\n attachment: Attachment;\n mimeOverride?: string;\n}\n\n/** Resolve the on-disk filename for an attachment. */\nfunction filenameForAttachment(input: FilenameForAttachmentInput): string {\n const preferred = resolvePreferredFilename(input);\n if (preferred) return preferred;\n const fallback = sanitizeFilename({\n value: `${input.attachment.id}${extensionForAttachment({ attachment: input.attachment, mimeOverride: input.mimeOverride })}`,\n });\n return fallback ?? input.attachment.id;\n}\n\nfunction resolvePreferredFilename(input: FilenameForAttachmentInput): string | undefined {\n const preferred = sanitizeFilename({ value: input.attachment.filename });\n if (preferred)\n return withMissingExtension({\n filename: preferred,\n attachment: input.attachment,\n mimeOverride: input.mimeOverride,\n });\n return sanitizeFilename({ value: filenameFromUrl({ url: input.attachment.url }) });\n}\n\n// --- attachments/download-http.helpers.ts ---\n\ninterface ResolveDownloadPathInput {\n outDir: string;\n attachment: Attachment;\n attachments: Attachment[];\n mimeOverride?: string;\n}\n\n/** Resolve a unique download path, disambiguating filename collisions. */\nasync function resolveDownloadPath(input: ResolveDownloadPathInput): Promise<string> {\n const filename = filenameForAttachment({\n attachment: input.attachment,\n mimeOverride: input.mimeOverride,\n });\n const filePath = outputPath({ outDir: input.outDir, filename });\n if ((await existingSize({ filePath })) === undefined) return filePath;\n return resolveCollidingDownloadPath({ input, filename, filePath });\n}\n\nasync function resolveCollidingDownloadPath(input: {\n input: ResolveDownloadPathInput;\n filename: string;\n filePath: string;\n}): Promise<string> {\n const owner = input.input.attachments.find(\n (item) =>\n filenameForAttachment({ attachment: item, mimeOverride: input.input.mimeOverride }) ===\n input.filename,\n );\n if (!owner || isSameAttachment({ left: owner, right: input.input.attachment }))\n return input.filePath;\n return outputPath({\n outDir: input.input.outDir,\n filename: disambiguateFilename({ filename: input.filename, id: input.input.attachment.id }),\n });\n}\n\ninterface FetchBlobInput {\n page: Page;\n attachment: Attachment;\n}\n\n/** Fetch blob attachment bytes through the browser context. */\nasync function fetchBlobBytes(input: FetchBlobInput): Promise<Buffer> {\n try {\n const bytes = await input.page.evaluate(async (url: string): Promise<number[] | Uint8Array> => {\n const response = await fetch(url);\n if (!response.ok) throw new Error(`Blob fetch failed with HTTP ${response.status}`);\n return new Uint8Array(await response.arrayBuffer());\n }, input.attachment.url);\n return Buffer.from(bytes);\n } catch (error) {\n throw new AttachmentDownloadError(\n input.attachment.id,\n input.attachment.url,\n `Failed to fetch blob attachment ${input.attachment.id}`,\n error,\n );\n }\n}\n\ninterface DownloadHttpInput {\n page: Page;\n attachment: Attachment;\n outDir: string;\n attachments: Attachment[];\n}\n\n/** Download an https attachment through the browser request context. */\nasync function downloadHttpAttachment(input: DownloadHttpInput): Promise<DownloadResult> {\n const response = await input.page.context().request.get(input.attachment.url);\n if (!response.ok())\n throwFailedHttpAttachment({ attachment: input.attachment, status: response.status() });\n return await saveHttpAttachmentResponse({\n outDir: input.outDir,\n attachment: input.attachment,\n attachments: input.attachments,\n response,\n });\n}\n\n// --- attachments/download-http.save.ts ---\n\n/** Save an HTTP attachment response body when content changed. */\nasync function saveHttpAttachmentResponse(input: {\n outDir: string;\n attachment: Attachment;\n attachments: Attachment[];\n response: APIResponse;\n}): Promise<DownloadResult> {\n const headers = input.response.headers();\n const filePath = await resolveDownloadPath({\n outDir: input.outDir,\n attachment: input.attachment,\n attachments: input.attachments,\n mimeOverride: headers[\"content-type\"],\n });\n const contentLength = Number(headers[\"content-length\"]);\n if (Number.isSafeInteger(contentLength) && (await existingSize({ filePath })) === contentLength) {\n return { path: filePath, bytes: contentLength };\n }\n return writeIfChanged({ filePath, bytes: await input.response.body() });\n}\n\n/** Throw when an HTTP attachment response is not successful. */\nfunction throwFailedHttpAttachment(input: {\n attachment: Attachment;\n status: number;\n}): void {\n throw new AttachmentDownloadError(\n input.attachment.id,\n input.attachment.url,\n `Attachment ${input.attachment.id} request failed with HTTP ${input.status}`,\n );\n}\n\n// --- attachments/download-path.helpers.ts ---\n\ninterface OutputDirectoryInput {\n /** Conversation id used for the default downloads folder. */\n conversationId: string;\n /** Optional explicit output directory. */\n outDir?: string;\n /** Repo root whose `.bridge/downloads` holds the default output directory. */\n repoRoot?: string;\n}\n\n/**\n * Resolve the output directory for attachment downloads.\n *\n * When no explicit `outDir` is given, downloads land in the repo-local,\n * self-ignoring `.bridge/downloads/<conversationId>` — so agents never have to\n * pass a destination and nothing leaks into git.\n */\nfunction outputDirectory(input: OutputDirectoryInput): string {\n if (input.outDir) return path.resolve(input.outDir);\n const repoRoot = input.repoRoot ?? process.cwd();\n return path.resolve(repoRoot, \".bridge\", \"downloads\", input.conversationId);\n}\n\ninterface OutputPathInput {\n /** Resolved output directory. */\n outDir: string;\n /** Filename relative to the output directory. */\n filename: string;\n}\n\n/** Build a safe absolute output path inside the output directory. */\nfunction outputPath(input: OutputPathInput): string {\n const resolvedOutDir = path.resolve(input.outDir);\n const filePath = path.resolve(resolvedOutDir, input.filename);\n const relativePath = path.relative(resolvedOutDir, filePath);\n if (relativePath.startsWith(\"..\") || path.isAbsolute(relativePath)) {\n throw new AttachmentDownloadError(\n \"\",\n undefined,\n `Invalid attachment output path: ${input.filename}`,\n );\n }\n return filePath;\n}\n\n/** Whether a URL uses HTTP or HTTPS. */\nfunction isHttpUrl(url: string): boolean {\n return url.startsWith(\"https://\") || url.startsWith(\"http://\");\n}\n\ninterface DisambiguateInput {\n /** Original filename that collided. */\n filename: string;\n /** Attachment id appended to disambiguate. */\n id: string;\n}\n\n/** Append an attachment id before the extension to avoid filename collisions. */\nfunction disambiguateFilename(input: DisambiguateInput): string {\n const extension = path.extname(input.filename);\n if (!extension) return `${input.filename}-${input.id}`;\n return `${input.filename.slice(0, -extension.length)}-${input.id}${extension}`;\n}\n\n// --- attachments/download-write.helpers.ts ---\n\ninterface ExistingSizeInput {\n /** Absolute file path to stat. */\n filePath: string;\n}\n\n/** Return file size when the path exists. */\nasync function existingSize(input: ExistingSizeInput): Promise<number | undefined> {\n try {\n return (await stat(input.filePath)).size;\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") return undefined;\n throw error;\n }\n}\n\ninterface WriteIfChangedInput {\n /** Absolute destination path. */\n filePath: string;\n /** File contents to write when size differs. */\n bytes: Buffer;\n}\n\n/** Write bytes only when the destination size changed. */\nasync function writeIfChanged(input: WriteIfChangedInput): Promise<DownloadResult> {\n if ((await existingSize({ filePath: input.filePath })) === input.bytes.byteLength) {\n return { path: input.filePath, bytes: input.bytes.byteLength };\n }\n await writeFile(input.filePath, input.bytes);\n return { path: input.filePath, bytes: input.bytes.byteLength };\n}\n\n// --- attachments/extract-messages.helpers.ts ---\n\nasync function persistAllMessages(params: {\n messages: SerializedMessage[];\n opts: ExtractMessagesOptions;\n}): Promise<Array<{ role: string; content: string; attachments: Attachment[] }>> {\n const manifest = await loadManifest(params.opts.conversationId);\n const state = {\n manifest,\n counters: countersFromManifest(manifest),\n now: new Date().toISOString(),\n };\n const captured = await mapCapturedMessages({ ...params, ...state });\n return saveCapturedMessages({ captured, manifest: state.manifest, counters: state.counters });\n}\n\nasync function saveCapturedMessages(params: {\n captured: Array<{ role: string; content: string; attachments: Attachment[] }>;\n manifest: Awaited<ReturnType<typeof loadManifest>>;\n counters: ReturnType<typeof countersFromManifest>;\n}) {\n params.manifest.counters = params.counters;\n await saveManifest(params.manifest);\n return params.captured;\n}\n\nasync function mapCapturedMessages(params: {\n messages: SerializedMessage[];\n opts: ExtractMessagesOptions;\n manifest: Awaited<ReturnType<typeof loadManifest>>;\n counters: ReturnType<typeof countersFromManifest>;\n now: string;\n}) {\n const captured: Array<{ role: string; content: string; attachments: Attachment[] }> = [];\n for (const message of params.messages) {\n captured.push(\n await captureMessage({\n message,\n opts: params.opts,\n counters: params.counters,\n now: params.now,\n manifest: params.manifest,\n }),\n );\n }\n return captured;\n}\n\nasync function captureMessage(params: {\n message: SerializedMessage;\n opts: ExtractMessagesOptions;\n counters: ReturnType<typeof countersFromManifest>;\n now: string;\n manifest: Awaited<ReturnType<typeof loadManifest>>;\n}) {\n if (!shouldRegisterAttachments({ message: params.message, opts: params.opts })) {\n return { role: params.message.role, content: params.message.text, attachments: [] };\n }\n return registerMessageAttachments(params);\n}\n\nasync function registerMessageAttachments(params: {\n message: SerializedMessage;\n counters: ReturnType<typeof countersFromManifest>;\n now: string;\n manifest: Awaited<ReturnType<typeof loadManifest>>;\n}) {\n const role: AttachmentRole = params.message.role === \"user\" ? \"user\" : \"assistant\";\n const registered = assignAttachmentIds({\n extracted: extractContentFromSnapshot(params.message.root),\n role,\n messageIndex: params.message.messageIndex,\n counters: params.counters,\n createdAt: params.now,\n existing: params.manifest.attachments,\n });\n params.manifest.attachments.push(...registered.newAttachments);\n return {\n role: params.message.role,\n content: registered.text,\n attachments: registered.attachments,\n };\n}\n\nfunction shouldRegisterAttachments(params: {\n message: SerializedMessage;\n opts: ExtractMessagesOptions;\n}): boolean {\n if (params.message.role === \"assistant\") return true;\n return params.message.role === \"user\" && params.opts.includeUserAttachments === true;\n}\n\n// --- attachments/extract-messages.ts ---\n\n/** Extract text and assistant attachments from the last assistant message. */\nasync function extractAssistantContent(\n page: Page,\n opts: { conversationId: string },\n): Promise<{ text: string; attachments: Attachment[] }> {\n const message = await page.evaluate<SerializedMessage | null>(\n LAST_ASSISTANT_MESSAGE_SNAPSHOT_SOURCE,\n );\n if (!message) return { text: \"\", attachments: [] };\n return registerExtractedContent({\n conversationId: opts.conversationId,\n messageIndex: message.messageIndex,\n extracted: extractContentFromSnapshot(message.root),\n });\n}\n\n/** Extract all rendered messages while registering assistant attachments and, optionally, user attachments. */\nasync function extractAllMessages(\n page: Page,\n opts: ExtractMessagesOptions,\n): Promise<Array<{ role: string; content: string; attachments: Attachment[] }>> {\n const messages = await page.evaluate<SerializedMessage[]>(ALL_MESSAGES_SNAPSHOT_SOURCE);\n return persistAllMessages({ messages, opts });\n}\n\n// --- attachments/manifest-counters.ts ---\n\n/** Supported attachment kinds tracked in manifests. */\nfunction attachmentKinds(): AttachmentKind[] {\n return [\"image\", \"file\", \"pdf\"];\n}\n\n/** Empty per-role attachment counters. */\nfunction emptyCounters(): AttachmentCounters {\n return {\n assistant: { image: 0, file: 0, pdf: 0 },\n user: { image: 0, file: 0, pdf: 0 },\n };\n}\n\n/** Build counters from existing attachment ids in a manifest. */\nfunction countersFromAttachments(attachments: Attachment[]): AttachmentCounters {\n const counters = emptyCounters();\n for (const attachment of attachments) {\n const suffix = Number(attachment.id.split(\"-\").at(-1));\n if (Number.isFinite(suffix)) {\n counters[attachment.role][attachment.kind] = Math.max(\n counters[attachment.role][attachment.kind],\n suffix,\n );\n }\n }\n return counters;\n}\n\n/** Merge stored counters with legacy or partial overrides. */\nfunction mergeCounters(base: AttachmentCounters, overrides: unknown): AttachmentCounters {\n const normalizedOverrides = normalizeCounters(overrides);\n return {\n assistant: {\n image: Math.max(base.assistant.image, normalizedOverrides.assistant.image),\n file: Math.max(base.assistant.file, normalizedOverrides.assistant.file),\n pdf: Math.max(base.assistant.pdf, normalizedOverrides.assistant.pdf),\n },\n user: {\n image: Math.max(base.user.image, normalizedOverrides.user.image),\n file: Math.max(base.user.file, normalizedOverrides.user.file),\n pdf: Math.max(base.user.pdf, normalizedOverrides.user.pdf),\n },\n };\n}\n\n/** Normalize unknown counter payloads into the current per-role shape. */\nfunction normalizeCounters(value: unknown): AttachmentCounters {\n const counters = emptyCounters();\n if (!isRecord(value)) return counters;\n return applyLegacyCounters({ counters, value });\n}\n\nfunction applyLegacyCounters(params: {\n counters: AttachmentCounters;\n value: Record<string, unknown>;\n}): AttachmentCounters {\n applyRoleCounters({\n counters: params.counters,\n role: \"assistant\",\n source: params.value.assistant,\n });\n applyRoleCounters({ counters: params.counters, role: \"user\", source: params.value.user });\n if (isKindCounters(params.value))\n applyRoleCounters({ counters: params.counters, role: \"assistant\", source: params.value });\n return params.counters;\n}\n\n/** Merge one role's kind counters with optional legacy overrides. */\nfunction mergeKindCounters(\n base: Record<AttachmentKind, number>,\n overrides: LegacyAttachmentCounters,\n): Record<AttachmentKind, number> {\n return {\n image: Math.max(base.image, overrides.image ?? 0),\n file: Math.max(base.file, overrides.file ?? 0),\n pdf: Math.max(base.pdf, overrides.pdf ?? 0),\n };\n}\n\nfunction applyRoleCounters(params: {\n counters: AttachmentCounters;\n role: \"assistant\" | \"user\";\n source: unknown;\n}): void {\n if (!isKindCounters(params.source)) return;\n params.counters[params.role] = mergeKindCounters(params.counters[params.role], params.source);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isKindCounters(value: unknown): value is LegacyAttachmentCounters {\n const kinds = attachmentKinds();\n return (\n isRecord(value) &&\n kinds.some((kind) => value[kind] !== undefined) &&\n kinds.every((kind) => value[kind] === undefined || typeof value[kind] === \"number\")\n );\n}\n\n// --- attachments/manifest-store.ts ---\n\nfunction manifestPath(conversationId: string): string {\n const downloadsRoot = path.resolve(process.cwd(), \"downloads\");\n const filePath = path.resolve(downloadsRoot, conversationId, \"manifest.json\");\n if (!filePath.startsWith(`${downloadsRoot}${path.sep}`)) {\n throw new Error(`Invalid conversation id for attachment manifest: ${conversationId}`);\n }\n return filePath;\n}\n\nfunction normalizeAttachment(attachment: SerializedAttachment): Attachment {\n return { ...attachment, role: attachment.role ?? \"assistant\" };\n}\n\nfunction normalizeManifest(params: {\n conversationId: string;\n manifest: Partial<AttachmentManifest>;\n}): AttachmentManifest {\n const attachments = Array.isArray(params.manifest.attachments)\n ? params.manifest.attachments.map(normalizeAttachment)\n : [];\n return {\n conversationId: params.manifest.conversationId ?? params.conversationId,\n attachments,\n counters: mergeCounters(countersFromAttachments(attachments), params.manifest.counters),\n };\n}\n\n/** Load a conversation attachment manifest, creating an empty one if needed. */\nasync function loadManifest(conversationId: string): Promise<AttachmentManifest> {\n try {\n const raw = await readFile(manifestPath(conversationId), \"utf8\");\n return normalizeManifest({\n conversationId,\n manifest: JSON.parse(raw) as Partial<AttachmentManifest>,\n });\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") {\n return { conversationId, attachments: [], counters: emptyCounters() };\n }\n throw error;\n }\n}\n\n/** Persist a conversation attachment manifest. */\nasync function saveManifest(manifest: AttachmentManifest): Promise<void> {\n const normalized = normalizeManifest({ conversationId: manifest.conversationId, manifest });\n const filePath = manifestPath(normalized.conversationId);\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, `${JSON.stringify(normalized, null, 2)}\\n`, \"utf8\");\n}\n\n/** Append already registered attachments to a conversation manifest. */\nasync function appendAttachments(\n conversationId: string,\n items: Attachment[],\n): Promise<AttachmentManifest> {\n const manifest = await loadManifest(conversationId);\n manifest.attachments.push(...items);\n manifest.counters = countersFromManifest(manifest);\n await saveManifest(manifest);\n return manifest;\n}\n\n/** Derive attachment counters from a manifest's stored attachments and overrides. */\nfunction countersFromManifest(manifest: AttachmentManifest): AttachmentCounters {\n return mergeCounters(countersFromAttachments(manifest.attachments), manifest.counters);\n}\n\n// --- attachments/snapshot-mime.ts ---\n\nconst EXTENSION_MIMES = [\n [\".pdf\", \"application/pdf\"],\n [\".png\", \"image/png\"],\n [\".jpg\", \"image/jpeg\"],\n [\".jpeg\", \"image/jpeg\"],\n [\".webp\", \"image/webp\"],\n [\".gif\", \"image/gif\"],\n] as const;\n\nfunction inferMimeFromDataUrl(url: string): string | undefined {\n const dataMatch = /^data:([^;,]+)/.exec(url);\n return dataMatch?.[1];\n}\n\nfunction inferMimeFromExtension(params: { url: string; fallback: AttachmentKind }):\n | string\n | undefined {\n const lower = params.url.split(\"?\")[0]?.toLowerCase() ?? \"\";\n const mapped = extensionMime(lower);\n if (mapped) return mapped;\n return params.fallback === \"image\" ? \"image/*\" : undefined;\n}\n\nfunction extensionMime(path: string): string | undefined {\n for (const [suffix, mime] of EXTENSION_MIMES) {\n if (path.endsWith(suffix)) return mime;\n }\n return undefined;\n}\n\nfunction inferMime(params: { url: string; fallback: AttachmentKind }): string | undefined {\n return inferMimeFromDataUrl(params.url) ?? inferMimeFromExtension(params);\n}\n\n// --- attachments/snapshot-walk.helpers.ts ---\n\nfunction readAttr(params: { node: Extract<DomSnapshotNode, { type: \"element\" }>; name: string }):\n | string\n | undefined {\n return params.node.attributes[params.name];\n}\n\nfunction optionalText(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction textOnly(node: DomSnapshotNode): string {\n if (node.type === \"text\") return node.text;\n return node.children.map(textOnly).join(\"\");\n}\n\nfunction isFileLink(node: Extract<DomSnapshotNode, { type: \"element\" }>): boolean {\n if (readAttr({ node, name: \"download\" }) !== undefined) return true;\n const href = readAttr({ node, name: \"href\" }) ?? \"\";\n const label =\n `${readAttr({ node, name: \"aria-label\" }) ?? \"\"} ${readAttr({ node, name: \"data-testid\" }) ?? \"\"}`.toLowerCase();\n return href.startsWith(\"blob:\") || label.includes(\"download\") || label.includes(\"file\");\n}\n\nfunction attachmentFromImage(node: Extract<DomSnapshotNode, { type: \"element\" }>) {\n const url = readAttr({ node, name: \"currentSrc\" }) || readAttr({ node, name: \"src\" });\n if (!url) return null;\n return {\n kind: \"image\" as const,\n url,\n filename: optionalText(readAttr({ node, name: \"alt\" })),\n mime: inferMime({ url, fallback: \"image\" }),\n };\n}\n\nfunction attachmentFromIframe(node: Extract<DomSnapshotNode, { type: \"element\" }>) {\n const url = readAttr({ node, name: \"src\" });\n if (!url) return null;\n return {\n kind: \"pdf\" as const,\n url,\n filename: optionalText(\n readAttr({ node, name: \"title\" }) || readAttr({ node, name: \"aria-label\" }),\n ),\n mime: \"application/pdf\",\n };\n}\n\nfunction attachmentFromFileLink(node: Extract<DomSnapshotNode, { type: \"element\" }>) {\n const url = readAttr({ node, name: \"href\" });\n if (!url) return null;\n return {\n kind: \"file\" as const,\n url,\n filename: optionalText(readAttr({ node, name: \"download\" })) ?? optionalText(textOnly(node)),\n mime: inferMime({ url, fallback: \"file\" }),\n };\n}\n\nfunction attachmentFromElement(node: Extract<DomSnapshotNode, { type: \"element\" }>) {\n if (node.tagName === \"img\") return attachmentFromImage(node);\n if (node.tagName === \"iframe\") return attachmentFromIframe(node);\n if (node.tagName === \"a\" && isFileLink(node)) return attachmentFromFileLink(node);\n return null;\n}\n\n// --- attachments/snapshot-walk.ts ---\n\n/** Convert a DOM snapshot into text with temporary attachment markers. */\nfunction extractContentFromSnapshot(root: DomSnapshotNode): ExtractedContent {\n const attachments: AttachmentCandidate[] = [];\n const text = walkSnapshot({ node: root, attachments });\n return { text, attachments };\n}\n\nfunction walkSnapshot(params: {\n node: DomSnapshotNode;\n attachments: AttachmentCandidate[];\n}): string {\n if (params.node.type === \"text\") {\n return typeof params.node.text === \"string\" ? params.node.text : \"\";\n }\n const attachment = attachmentFromElement(params.node);\n if (attachment) {\n params.attachments.push(attachment);\n return markerFor(params.attachments.length - 1);\n }\n if (params.node.tagName === \"br\") return \"\\n\";\n return params.node.children\n .map((child) => walkSnapshot({ node: child, attachments: params.attachments }))\n .join(\"\");\n}\n\n// --- connector.constants.ts ---\n/** Default connector display name used when none is provided in setup options. */\nconst DEFAULT_CONNECTOR_NAME = \"ai-browser-bridge\";\n\n/** Prefix identifying bridge-owned connector apps in ChatGPT settings. */\nconst BRIDGE_CONNECTOR_PREFIX = \"ai-browser-bridge\";\n\n// --- connector/accept-custom-mcp-risk.ts ---\n\n/** Context for {@link isRiskCheckboxVisible}. */\ninterface IsRiskCheckboxVisibleContext {\n /** Connector setup context with page handle. */\n setup: ConnectorSetupContext;\n}\n\n/** True when the custom MCP risk checkbox is visible in the form. */\nasync function isRiskCheckboxVisible(ctx: IsRiskCheckboxVisibleContext): Promise<boolean> {\n const checkbox = ctx.setup.page\n .locator('input[data-testid=\"trust-checkbox\"], input[type=\"checkbox\"]')\n .first();\n if ((await checkbox.count()) === 0) return false;\n return checkbox.isVisible().catch(() => false);\n}\n\n/** Accept the custom MCP risk checkbox when ChatGPT shows it in the form. */\nasync function acceptCustomMcpRiskIfPresent(ctx: ConnectorSetupContext): Promise<boolean> {\n if (!(await isRiskCheckboxVisible({ setup: ctx }))) return false;\n const checkbox = ctx.page\n .locator('input[data-testid=\"trust-checkbox\"], input[type=\"checkbox\"]')\n .first();\n if (await checkbox.isChecked().catch(() => false)) return true;\n await checkbox.check({ force: true });\n return true;\n}\n\n// --- connector/append-unique-summary.ts ---\n\n/** Context for {@link appendUniqueSummary}. */\ninterface AppendUniqueSummaryContext {\n /** Accumulated connector summaries. */\n summaries: ConnectorAppSummary[];\n /** Keys already collected while enumerating connectors. */\n seen: Set<string>;\n /** Candidate summary to append when unique. */\n summary: ConnectorAppSummary | null;\n}\n\n/** Append a summary when its deduplication key has not been seen. */\nfunction appendUniqueSummary(ctx: AppendUniqueSummaryContext): void {\n if (!ctx.summary) return;\n const key = connectorSummaryKey({ summary: ctx.summary });\n if (ctx.seen.has(key)) return;\n ctx.seen.add(key);\n ctx.summaries.push(ctx.summary);\n}\n\n// --- connector/chatgpt-return-url.ts ---\n/** Context for {@link chatGptReturnUrl}. */\ninterface ChatGptReturnUrlContext {\n /** Current browser URL to normalize into a restorable ChatGPT location. */\n url: string;\n}\n\n/** Normalize a ChatGPT URL into a conversation or home URL suitable for restoration. */\nfunction chatGptReturnUrl(ctx: ChatGptReturnUrlContext): string | null {\n try {\n const parsed = new URL(ctx.url);\n if (!parsed.hostname.endsWith(\"chatgpt.com\")) return null;\n parsed.hash = \"\";\n parsed.search = \"\";\n if (parsed.pathname.startsWith(\"/c/\")) return parsed.toString();\n return `${parsed.origin}/`;\n } catch {\n return null;\n }\n}\n\n// --- connector/cleanup-duplicate-connector-apps.ts ---\n\n/** Context for {@link findDeleteTargets}. */\ninterface FindDeleteTargetsContext {\n /** Connector summaries currently listed in settings. */\n summaries: ConnectorAppSummary[];\n /** Desired connector display name. */\n connectorName: string;\n /** Desired connector MCP URL. */\n connectorUrl: string;\n}\n\n/** Select connector summaries that should be deleted as duplicates or stale entries. */\nfunction findDeleteTargets(ctx: FindDeleteTargetsContext): ConnectorAppSummary[] {\n const current =\n ctx.summaries.find(\n (summary) => summary.name === ctx.connectorName && summary.url === ctx.connectorUrl,\n ) ?? null;\n return ctx.summaries.filter((summary) => {\n if (summary.name !== ctx.connectorName) return true;\n if (summary.url !== ctx.connectorUrl) return true;\n return !!current && !sameConnectorApp({ a: summary, b: current });\n });\n}\n\n/** Remove duplicate bridge connector apps and return whether the desired connector exists. */\nasync function cleanupDuplicateConnectorApps(ctx: ConnectorSetupContext): Promise<boolean> {\n const summaries = await listBridgeConnectorSummaries({ page: ctx.page });\n const current =\n summaries.find(\n (summary) => summary.name === ctx.connectorName && summary.url === ctx.connectorUrl,\n ) ?? null;\n await deleteDuplicateTargets({\n setup: ctx,\n deleteTargets: findDeleteTargets({\n summaries,\n connectorName: ctx.connectorName,\n connectorUrl: ctx.connectorUrl,\n }),\n });\n await openConnectorList({ page: ctx.page });\n return !!current;\n}\n\n// --- connector/click-connector-details-button.ts ---\n\n/** Context for {@link clickConnectorDetailsButton}. */\ninterface ClickConnectorDetailsButtonContext {\n /** Connector list button locator. */\n button: Locator;\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n}\n\n/** Click a connector list button and record the opened step. */\nasync function clickConnectorDetailsButton(ctx: ClickConnectorDetailsButtonContext): Promise<void> {\n await ctx.button.click({ timeout: 3_000, force: true });\n await ctx.setup.page.waitForTimeout(1_000);\n ctx.setup.result.steps.push(`Opened existing connector: ${ctx.setup.connectorName}.`);\n}\n\n// --- connector/click-connector-entry-button.ts ---\n\n/** Context for {@link clickConnectorEntryButton}. */\ninterface ClickConnectorEntryButtonContext {\n /** Connector list button locator. */\n button: Locator;\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Click a connector list entry and wait for its detail panel. */\nasync function clickConnectorEntryButton(ctx: ClickConnectorEntryButtonContext): Promise<void> {\n await ctx.button.click({ timeout: 3_000, force: true });\n await ctx.page.waitForTimeout(1_000);\n}\n\n// --- connector/click-connector-from-more-menu.ts ---\n\n/** Click the connector entry from the composer More submenu when needed. */\nasync function clickConnectorFromMoreMenu(ctx: ConnectorSetupContext): Promise<boolean> {\n if (!(await hoverAndClickMoreMenuItem({ setup: ctx }))) return false;\n return clickConnectorMenuItem({ page: ctx.page, connectorName: ctx.connectorName });\n}\n\n// --- connector/click-connector-list-entry.ts ---\n\n/** Context for {@link clickConnectorListEntry}. */\ninterface ClickConnectorListEntryContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Zero-based connector button index in the list. */\n index: number;\n}\n\n/** Open one connector list entry by index. */\nasync function clickConnectorListEntry(ctx: ClickConnectorListEntryContext): Promise<boolean> {\n await openConnectorList({ page: ctx.page });\n const entry = (await findBridgeConnectorButtons({ page: ctx.page }))[ctx.index];\n if (!entry) return false;\n await clickConnectorEntryButton({ button: entry.button, page: ctx.page });\n return true;\n}\n\n// --- connector/click-connector-menu-item.ts ---\n\n/** Context for {@link clickConnectorMenuItem}. */\ninterface ClickConnectorMenuItemContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: ConnectorSetupContext[\"page\"];\n /** Connector display name to click in the menu. */\n connectorName: string;\n}\n\n/** Click a connector entry in the composer plus-menu. */\nasync function clickConnectorMenuItem(ctx: ClickConnectorMenuItemContext): Promise<boolean> {\n const item = ctx.page\n .locator(\n `[role=\"menu\"] [role=\"menuitem\"]:has-text(\"${ctx.connectorName}\"), [role=\"menu\"] button:has-text(\"${ctx.connectorName}\"), [role=\"menu\"] :text-is(\"${ctx.connectorName}\")`,\n )\n .last();\n if (!(await item.isVisible().catch(() => false))) return false;\n await item.click({ timeout: 3_000, force: true });\n await ctx.page.waitForTimeout(500);\n return true;\n}\n\n// --- connector/click-delete-confirmation.ts ---\n\n/** Context for {@link clickDeleteConfirmation}. */\ninterface ClickDeleteConfirmationContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Confirm connector deletion in the alert or dialog that appears. */\nasync function clickDeleteConfirmation(ctx: ClickDeleteConfirmationContext): Promise<void> {\n await clickFirstVisible({\n page: ctx.page,\n selectors: [\n '[role=\"alertdialog\"] button:has-text(\"Delete\")',\n '[role=\"dialog\"] button:has-text(\"Delete\")',\n 'button:has-text(\"Delete app\")',\n 'button:has-text(\"Delete App\")',\n ],\n timeout: 1_000,\n });\n await ctx.page.waitForTimeout(2_000);\n}\n\n// --- connector/click-delete-menu-item.ts ---\n\n/** Context for {@link clickDeleteMenuItem}. */\ninterface ClickDeleteMenuItemContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Click Delete in the connector manage menu when visible. */\nasync function clickDeleteMenuItem(ctx: ClickDeleteMenuItemContext) {\n return firstVisible({\n page: ctx.page,\n selectors: [\n '[role=\"menu\"] [role=\"menuitem\"]:has-text(\"Delete\")',\n '[data-radix-menu-content] [role=\"menuitem\"]:has-text(\"Delete\")',\n ],\n });\n}\n\n// --- connector/click-more-menu-item.ts ---\n\n/** Context for {@link clickMoreMenuItem}. */\ninterface ClickMoreMenuItemContext {\n /** More submenu item locator. */\n moreItem: Locator;\n /** Connector setup context with page handle. */\n setup: ConnectorSetupContext;\n}\n\n/** Hover and click the More submenu entry in the composer menu. */\nasync function clickMoreMenuItem(ctx: ClickMoreMenuItemContext): Promise<void> {\n await ctx.moreItem.hover().catch(() => {});\n await ctx.moreItem.click({ timeout: 2_000, force: true }).catch(() => {});\n await ctx.setup.page.waitForTimeout(750);\n}\n\n// --- connector/click-settings-entry.ts ---\n\n/** Context for {@link clickSettingsEntry}. */\ninterface ClickSettingsEntryContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n}\n\n/** Click Settings in the account menu and record the outcome. */\nasync function clickSettingsEntry(ctx: ClickSettingsEntryContext): Promise<void> {\n const openedSettings = await clickFirstVisible({\n page: ctx.setup.page,\n selectors: SELECTORS.settingsEntrypoint,\n timeout: 2_000,\n });\n if (openedSettings) {\n ctx.setup.result.steps.push(\"Opened ChatGPT settings.\");\n await ctx.setup.page.waitForTimeout(1_000);\n } else {\n ctx.setup.result.warnings.push(\"Could not find Settings in the account menu.\");\n }\n}\n\n// --- connector/close-settings-dialog.ts ---\n\n/** Close the settings dialog when a close button is visible. */\nasync function closeSettingsDialogIfPresent(ctx: ConnectorSetupContext): Promise<void> {\n const closeButton = await firstVisible({\n page: ctx.page,\n selectors: [\n '[role=\"dialog\"] button[aria-label=\"Close\"]',\n '[role=\"dialog\"] [data-testid=\"close-button\"]',\n ],\n });\n if (closeButton) {\n await closeButton.click({ timeout: 2_000, force: true }).catch(() => {});\n await ctx.page.waitForTimeout(500);\n }\n}\n\n// --- connector/confirm-open-connector-deletion.ts ---\n\n/** Context for {@link clickDeleteMenuEntry}. */\ninterface ClickDeleteMenuEntryContext {\n /** Delete menu item locator. */\n deleteItem: Locator;\n /** Playwright page handle for the ChatGPT tab. */\n page: import(\"playwright\").Page;\n}\n\n/** Click the delete menu entry and confirm deletion. */\nasync function clickDeleteMenuEntry(ctx: ClickDeleteMenuEntryContext): Promise<void> {\n await ctx.deleteItem.click({ timeout: 2_000, force: true });\n await ctx.page.waitForTimeout(500);\n await clickDeleteConfirmation({ page: ctx.page });\n}\n\n/** Context for {@link confirmOpenConnectorDeletion}. */\ninterface ConfirmOpenConnectorDeletionContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: import(\"playwright\").Page;\n}\n\n/** Confirm deletion for the currently open connector detail panel. */\nasync function confirmOpenConnectorDeletion(\n ctx: ConfirmOpenConnectorDeletionContext,\n): Promise<boolean> {\n const deleteItem = await clickDeleteMenuItem({ page: ctx.page });\n if (!deleteItem) return false;\n await clickDeleteMenuEntry({ deleteItem, page: ctx.page });\n return true;\n}\n\n// --- connector/connector-composer-helpers.ts ---\n\n/** Context for {@link findSelectedConnectorPill}. */\ninterface FindSelectedConnectorPillContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: ConnectorSetupContext[\"page\"];\n /** Connector display name to match in pill aria-labels. */\n connectorName: string;\n}\n\n/** Find the selected connector pill in the composer by aria-label. */\nasync function findSelectedConnectorPill(\n ctx: FindSelectedConnectorPillContext,\n): Promise<Locator | null> {\n const buttons = await ctx.page.locator('button[aria-label*=\"click to remove\"]').all();\n for (const button of buttons) {\n const aria = await button.getAttribute(\"aria-label\").catch(() => null);\n if (aria === `${ctx.connectorName}, click to remove`) return button;\n }\n return null;\n}\n\n/** Context for {@link isConnectorSelectedInComposer}. */\ninterface IsConnectorSelectedInComposerContext {\n /** Connector setup context with page and connector name. */\n setup: ConnectorSetupContext;\n}\n\n/** True when the desired connector pill is already selected in the composer. */\nasync function isConnectorSelectedInComposer(\n ctx: IsConnectorSelectedInComposerContext,\n): Promise<boolean> {\n return !!(await findSelectedConnectorPill({\n page: ctx.setup.page,\n connectorName: ctx.setup.connectorName,\n }));\n}\n\n/** Remove stale bridge connector pills that are not the desired connector. */\nasync function removeStaleBridgeConnectorPills(ctx: ConnectorSetupContext): Promise<void> {\n const buttons = await ctx.page\n .locator('button[aria-label*=\"ai-browser-bridge\"][aria-label*=\"click to remove\"]')\n .all();\n for (const button of buttons) {\n const aria = await button.getAttribute(\"aria-label\").catch(() => null);\n if (!aria || aria === `${ctx.connectorName}, click to remove`) continue;\n await button.click({ timeout: 1_000, force: true }).catch(() => {});\n await ctx.page.waitForTimeout(250);\n }\n}\n\n// --- connector/connector-summary-helpers.ts ---\n\n/** Context for {@link normalizeConnectorListLabel}. */\ninterface NormalizeConnectorListLabelContext {\n /** Raw connector list button label text. */\n value: string;\n}\n\n/** Normalize connector list button labels for comparison. */\nfunction normalizeConnectorListLabel(ctx: NormalizeConnectorListLabelContext): string {\n return normalizeDisplayText({ value: ctx.value }).replace(/\\s+/g, \"\").replace(/DEV$/i, \"\");\n}\n\n/** Context for {@link valueAfterLine}. */\ninterface ValueAfterLineContext {\n /** Dialog text split into trimmed lines. */\n lines: string[];\n /** Label line whose following value should be read. */\n label: string;\n}\n\n/** Read the line immediately following a label in dialog text. */\nfunction valueAfterLine(ctx: ValueAfterLineContext): string | null {\n const index = ctx.lines.indexOf(ctx.label);\n const value = index >= 0 ? ctx.lines[index + 1] : null;\n return value?.trim() || null;\n}\n\n/** Context for {@link connectorSummaryKey}. */\ninterface ConnectorSummaryKeyContext {\n /** Connector app summary to key. */\n summary: { name: string; appId: string | null; url: string | null };\n}\n\n/** Build a deduplication key for connector summaries. */\nfunction connectorSummaryKey(ctx: ConnectorSummaryKeyContext): string {\n return `${ctx.summary.name}\\u0000${ctx.summary.appId ?? \"\"}\\u0000${ctx.summary.url ?? \"\"}`;\n}\n\n/** Context for {@link sameConnectorApp}. */\ninterface SameConnectorAppContext {\n /** First connector summary. */\n a: { appId: string | null; name: string; url: string | null };\n /** Second connector summary. */\n b: { appId: string | null; name: string; url: string | null };\n}\n\n/** True when two connector summaries refer to the same app. */\nfunction sameConnectorApp(ctx: SameConnectorAppContext): boolean {\n if (ctx.a.appId && ctx.b.appId) return ctx.a.appId === ctx.b.appId;\n return ctx.a.name === ctx.b.name && ctx.a.url === ctx.b.url;\n}\n\n// --- connector/connectorTypes.ts ---\n\n/** Mutable context passed through connector setup steps. */\ninterface ConnectorSetupContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** MCP connector URL to register in ChatGPT settings. */\n connectorUrl: string;\n /** Connector setup options from the caller. */\n options: ConnectorSetupOptions;\n /** Connector display name resolved from options or defaults. */\n connectorName: string;\n /** URL to restore after automatic setup attempts. */\n returnUrl: string | null;\n /** Accumulated setup result returned to the caller. */\n result: ConnectorSetupResult;\n}\n\n/** State of an existing connector relative to the desired URL. */\ntype ExistingConnectorState = \"missing\" | \"current\" | \"stale\" | \"unknown\";\n\n/** Summary of a bridge connector app listed in ChatGPT settings. */\ninterface ConnectorAppSummary {\n /** Connector display name shown in settings. */\n name: string;\n /** ChatGPT-assigned app id, when readable from the panel. */\n appId: string | null;\n /** Registered MCP endpoint URL, when readable from the panel. */\n url: string | null;\n}\n\n// --- connector/create-new-connector.ts ---\n\n/** Context for {@link warnMissingConnectorUrlField}. */\ninterface WarnMissingConnectorUrlFieldContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n}\n\n/** Record a warning and optionally restore the page when the URL field is missing. */\nasync function warnMissingConnectorUrlField(\n ctx: WarnMissingConnectorUrlFieldContext,\n): Promise<void> {\n ctx.setup.result.warnings.push(\n \"Could not find the connector URL field. The settings UI is open; paste the Connector URL manually.\",\n );\n if (ctx.setup.options.automatic) await restoreAfterConnectorSetup(ctx.setup);\n}\n\n/** Create a new connector through the settings UI form. */\nasync function createNewConnector(ctx: ConnectorSetupContext): Promise<void> {\n await openAdvancedSettingsIfPresent(ctx);\n await enableDeveloperModeIfPresent(ctx);\n await openCreateConnectorForm(ctx);\n if (!(await fillConnectorFormFields(ctx))) {\n await warnMissingConnectorUrlField({ setup: ctx });\n return;\n }\n await finishConnectorCreation({ setup: ctx });\n}\n\n// --- connector/delete-connector-app-by-summary.ts ---\n\n/** Context for {@link deleteConnectorAppBySummary}. */\ninterface DeleteConnectorAppBySummaryContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: ConnectorSetupContext[\"page\"];\n /** Connector summary identifying the app to delete. */\n target: ConnectorAppSummary;\n}\n\n/** Delete one connector app by locating and opening its summary panel. */\nasync function deleteConnectorAppBySummary(\n ctx: DeleteConnectorAppBySummaryContext,\n): Promise<boolean> {\n for (let attempt = 0; attempt < 3; attempt += 1) {\n await openConnectorList({ page: ctx.page });\n const entries = await findBridgeConnectorButtons({ page: ctx.page });\n for (const entry of entries) {\n if (entry.name !== ctx.target.name) continue;\n await entry.button.click({ timeout: 3_000, force: true });\n await ctx.page.waitForTimeout(1_000);\n const open = await readOpenConnectorSummary({ page: ctx.page });\n if (!open || !sameConnectorApp({ a: open, b: ctx.target })) continue;\n return deleteOpenConnectorIfPresent({ page: ctx.page });\n }\n }\n return false;\n}\n\n// --- connector/delete-duplicate-targets.ts ---\n\n/** Context for {@link deleteDuplicateTargets}. */\ninterface DeleteDuplicateTargetsContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n /** Connector summaries that should be deleted. */\n deleteTargets: ConnectorAppSummary[];\n}\n\n/** Delete duplicate connector apps and record steps or warnings. */\nasync function deleteDuplicateTargets(ctx: DeleteDuplicateTargetsContext): Promise<void> {\n for (const target of ctx.deleteTargets) {\n const deleted = await deleteConnectorAppBySummary({ page: ctx.setup.page, target });\n if (deleted) {\n ctx.setup.result.steps.push(\n `Deleted duplicate connector app: ${target.name}${target.url ? ` (${target.url})` : \"\"}.`,\n );\n } else {\n ctx.setup.result.warnings.push(`Could not delete duplicate connector app: ${target.name}.`);\n }\n }\n}\n\n// --- connector/delete-open-connector.ts ---\n\n/** Context for {@link deleteOpenConnectorIfPresent}. */\ninterface DeleteOpenConnectorIfPresentContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Delete the currently open connector via Manage -> Delete when available. */\nasync function deleteOpenConnectorIfPresent(\n ctx: DeleteOpenConnectorIfPresentContext,\n): Promise<boolean> {\n const manage = await firstVisible({\n page: ctx.page,\n selectors: ['[role=\"dialog\"] button:has-text(\"Manage\")'],\n });\n if (!manage) return false;\n await manage.click({ timeout: 2_000, force: true });\n await ctx.page.waitForTimeout(500);\n return confirmOpenConnectorDeletion({ page: ctx.page });\n}\n\n// --- connector/enable-developer-mode.dom-snippet.ts ---\n/** In-page script that toggles Developer mode when present in settings. */\nconst ENABLE_DEVELOPER_MODE_SNIPPET = `() => {\n const labels = Array.from(document.querySelectorAll(\"body *\"))\n .filter((node) => /Developer mode/i.test(node.textContent ?? \"\"));\n\n for (const label of labels.slice(0, 25)) {\n let scope = label;\n for (let depth = 0; scope && depth < 5; depth += 1, scope = scope.parentElement) {\n const controls = Array.from(scope.querySelectorAll(\n 'button[role=\"switch\"], input[type=\"checkbox\"], button[aria-checked], [data-state=\"checked\"], [data-state=\"unchecked\"]',\n ));\n for (const control of controls) {\n const ariaChecked = control.getAttribute(\"aria-checked\");\n const dataState = control.getAttribute(\"data-state\");\n const checkbox = control instanceof HTMLInputElement && control.type === \"checkbox\" ? control : null;\n const checked = ariaChecked === \"true\" || dataState === \"checked\" || checkbox?.checked === true;\n if (checked) return \"already-enabled\";\n if (control instanceof HTMLElement) {\n control.click();\n return \"enabled\";\n }\n }\n }\n }\n return \"not-found\";\n}`;\n\n// --- connector/enable-developer-mode.ts ---\n\n/** Enable Developer mode via in-page toggle discovery when available. */\nasync function enableDeveloperModeIfPresent(ctx: ConnectorSetupContext): Promise<void> {\n const outcome = await ctx.page.evaluate(ENABLE_DEVELOPER_MODE_SNIPPET);\n if (outcome === \"enabled\") {\n ctx.result.steps.push(\"Enabled Developer mode.\");\n await ctx.page.waitForTimeout(750);\n return;\n }\n if (outcome === \"already-enabled\") {\n ctx.result.steps.push(\"Developer mode was already enabled.\");\n return;\n }\n ctx.result.warnings.push(\n \"Could not find the Developer mode toggle. It may already be enabled or unavailable for this account/workspace.\",\n );\n}\n\n// --- connector/ensure-composer-connector-selected.ts ---\n\n/** Ensure the desired connector is selected in the composer, opening the menu if needed. */\nasync function ensureComposerConnectorSelected(ctx: ConnectorSetupContext): Promise<boolean> {\n if (await isConnectorSelectedInComposer({ setup: ctx })) return true;\n await removeStaleBridgeConnectorPills(ctx);\n if (await isConnectorSelectedInComposer({ setup: ctx })) return true;\n return openComposerConnectorMenu(ctx);\n}\n\n// --- connector/execute-connector-setup.ts ---\n\n/** Context for {@link runConnectorSetupSteps}. */\ninterface RunConnectorSetupStepsContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n /** Whether duplicate cleanup already found the current connector. */\n hasCurrentConnector: boolean;\n}\n\n/** Run post-settings connector setup steps after the settings panels are open. */\nasync function runConnectorSetupSteps(\n ctx: RunConnectorSetupStepsContext,\n): Promise<ConnectorSetupContext[\"result\"]> {\n if (\n await tryFinalizeExistingConnector({\n setup: ctx.setup,\n hasCurrentConnector: ctx.hasCurrentConnector,\n })\n ) {\n return ctx.setup.result;\n }\n if (!(await handleStaleExistingConnector(ctx.setup))) return ctx.setup.result;\n await createNewConnector(ctx.setup);\n return ctx.setup.result;\n}\n\n/** Run the full ChatGPT connector setup workflow. */\nasync function executeConnectorSetup(\n ctx: ConnectorSetupContext,\n): Promise<ConnectorSetupContext[\"result\"]> {\n await openChatGptSettings(ctx);\n await openAppsOrConnectorsPanel(ctx);\n const hasCurrentConnector = await cleanupDuplicateConnectorApps(ctx);\n return runConnectorSetupSteps({ setup: ctx, hasCurrentConnector });\n}\n\n// --- connector/fill-connector-form-fields.ts ---\n\n/** Context for {@link fillConnectorUrlField}. */\ninterface FillConnectorUrlFieldContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n}\n\n/** Fill the connector URL field and record a setup step when successful. */\nasync function fillConnectorUrlField(ctx: FillConnectorUrlFieldContext): Promise<boolean> {\n const filledUrl = await fillFirstVisible({\n page: ctx.setup.page,\n selectors: [\n 'input[name=\"custom-connector-url\"]',\n \"#custom-connector-url\",\n 'input[type=\"url\"]',\n 'input[name*=\"url\" i]',\n 'input[placeholder*=\"https://\" i]',\n 'input[placeholder*=\"url\" i]',\n 'textarea[name*=\"url\" i]',\n 'textarea[placeholder*=\"https://\" i]',\n ],\n value: ctx.setup.connectorUrl,\n });\n if (filledUrl) ctx.setup.result.steps.push(`Filled connector URL: ${ctx.setup.connectorUrl}`);\n return filledUrl;\n}\n\n/** Context for {@link fillConnectorNameField}. */\ninterface FillConnectorNameFieldContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n}\n\n/** Fill the connector name field and record a setup step when successful. */\nasync function fillConnectorNameField(ctx: FillConnectorNameFieldContext): Promise<void> {\n const filledName = await fillFirstVisible({\n page: ctx.setup.page,\n selectors: [\n 'input[name=\"custom-connector-name\"]',\n \"#custom-connector-name\",\n 'input[name*=\"name\" i]',\n 'input[placeholder*=\"name\" i]',\n 'input[aria-label*=\"name\" i]',\n ],\n value: ctx.setup.connectorName,\n });\n if (filledName) ctx.setup.result.steps.push(`Filled connector name: ${ctx.setup.connectorName}`);\n}\n\n/** Fill connector URL and name fields in the creation form. */\nasync function fillConnectorFormFields(ctx: ConnectorSetupContext): Promise<boolean> {\n if (!(await fillConnectorUrlField({ setup: ctx }))) return false;\n await fillConnectorNameField({ setup: ctx });\n return true;\n}\n\n// --- connector/finalize-current-connector.ts ---\n\n/** Finalize setup when an existing connector already uses the current URL. */\nasync function finalizeCurrentConnector(ctx: ConnectorSetupContext): Promise<void> {\n ctx.result.completed = true;\n ctx.result.steps.push(\"Existing connector already uses the current URL.\");\n if (await refreshOpenConnectorIfPresent(ctx)) {\n ctx.result.steps.push(\"Refreshed the connector tool schema.\");\n }\n await selectConnectorAfterSetup(ctx);\n}\n\n// --- connector/find-bridge-connector-buttons.ts ---\n\n/** Context for {@link findBridgeConnectorButtons}. */\ninterface FindBridgeConnectorButtonsContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Find bridge connector buttons in the open settings dialog. */\nasync function findBridgeConnectorButtons(\n ctx: FindBridgeConnectorButtonsContext,\n): Promise<Array<{ button: Locator; name: string }>> {\n const buttons = await ctx.page.locator('[role=\"dialog\"] button').all();\n const entries: Array<{ button: Locator; name: string }> = [];\n for (const button of buttons) {\n const label = normalizeConnectorListLabel({ value: await button.innerText().catch(() => \"\") });\n if (label.startsWith(BRIDGE_CONNECTOR_PREFIX)) {\n entries.push({ button, name: label });\n }\n }\n return entries;\n}\n\n// --- connector/find-connector-button.ts ---\n\n/** Context for {@link findConnectorButton}. */\ninterface FindConnectorButtonContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Connector display name to locate in the list. */\n connectorName: string;\n}\n\n/** Find a connector list button by exact normalized label. */\nasync function findConnectorButton(ctx: FindConnectorButtonContext): Promise<Locator | null> {\n const buttons = await ctx.page.locator('[role=\"dialog\"] button').all();\n for (const button of buttons) {\n const label = normalizeConnectorListLabel({ value: await button.innerText().catch(() => \"\") });\n if (label === ctx.connectorName) return button;\n }\n return null;\n}\n\n/** Context for {@link waitForConnectorButton}. */\ninterface WaitForConnectorButtonContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Connector display name to wait for. */\n connectorName: string;\n /** Maximum wait time in milliseconds. */\n timeoutMs: number;\n}\n\n/** Poll until a connector button becomes visible in settings. */\nasync function waitForConnectorButton(ctx: WaitForConnectorButtonContext): Promise<boolean> {\n const startedAt = Date.now();\n while (Date.now() - startedAt < ctx.timeoutMs) {\n const button = await findConnectorButton({ page: ctx.page, connectorName: ctx.connectorName });\n if (button && (await button.isVisible().catch(() => false))) return true;\n await ctx.page.waitForTimeout(500);\n }\n return false;\n}\n\n// --- connector/finish-connector-creation.ts ---\n\n/** Context for {@link recordConnectorFormOptions}. */\ninterface RecordConnectorFormOptionsContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n}\n\n/** Record optional auth and risk acceptance steps before submit. */\nasync function recordConnectorFormOptions(ctx: RecordConnectorFormOptionsContext): Promise<void> {\n if (await selectNoAuthenticationIfPresent(ctx.setup)) {\n ctx.setup.result.steps.push(\"Selected no-authentication option when visible.\");\n }\n if (await acceptCustomMcpRiskIfPresent(ctx.setup)) {\n ctx.setup.result.steps.push(\"Accepted custom MCP server risk notice.\");\n }\n}\n\n/** Context for {@link finishConnectorCreation}. */\ninterface FinishConnectorCreationContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n}\n\n/** Submit the connector form and restore the page on automatic failure. */\nasync function finishConnectorCreation(ctx: FinishConnectorCreationContext): Promise<void> {\n await recordConnectorFormOptions({ setup: ctx.setup });\n await submitConnectorForm(ctx.setup);\n if (ctx.setup.options.automatic && !ctx.setup.result.completed) {\n await restoreAfterConnectorSetup(ctx.setup);\n }\n}\n\n// --- connector/handle-stale-existing-connector.ts ---\n\n/** Handle stale or unknown existing connectors before creating a new one. */\nasync function handleStaleExistingConnector(ctx: ConnectorSetupContext): Promise<boolean> {\n const existing = await openExistingConnectorDetails(ctx);\n if (existing === \"stale\") return deleteStaleConnector(ctx);\n if (existing === \"unknown\") {\n ctx.result.warnings.push(\n \"Existing connector was found, but its URL could not be read from the settings panel.\",\n );\n }\n return true;\n}\n\n/** Delete a stale connector and reopen the connectors panel for recreation. */\nasync function deleteStaleConnector(ctx: ConnectorSetupContext): Promise<boolean> {\n if (await deleteOpenConnectorIfPresent({ page: ctx.page })) {\n ctx.result.steps.push(\n \"Deleted stale connector app before recreating it with the new tunnel URL.\",\n );\n await returnToConnectorListIfNeeded(ctx);\n await openAppsOrConnectorsPanel(ctx);\n await openAdvancedSettingsIfPresent(ctx);\n return true;\n }\n ctx.result.warnings.push(\n \"Existing connector uses an old tunnel URL, but ChatGPT did not expose a delete/update control.\",\n );\n if (ctx.options.automatic) await restoreAfterConnectorSetup(ctx);\n return false;\n}\n\n// --- connector/hover-and-click-more-menu-item.ts ---\n\n/** Context for {@link hoverAndClickMoreMenuItem}. */\ninterface HoverAndClickMoreMenuItemContext {\n /** Connector setup context with page handle. */\n setup: ConnectorSetupContext;\n}\n\n/** Hover and click the More submenu entry in the composer menu. */\nasync function hoverAndClickMoreMenuItem(ctx: HoverAndClickMoreMenuItemContext): Promise<boolean> {\n const moreItem = await firstVisible({\n page: ctx.setup.page,\n selectors: [\n '[role=\"menuitem\"][aria-haspopup=\"menu\"]:has-text(\"More\")',\n '[role=\"menuitem\"]:has-text(\"More\")',\n ],\n });\n if (!moreItem) return false;\n await clickMoreMenuItem({ moreItem, setup: ctx.setup });\n return true;\n}\n\n// --- connector/init-connector-setup-context.ts ---\n\n/** Input for initializing a connector setup context. */\ninterface InitConnectorSetupContextInput {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** MCP connector URL to register in ChatGPT settings. */\n connectorUrl: string;\n /** Connector setup options from the caller. */\n options: ConnectorSetupOptions;\n}\n\n/** Build a fully initialized connector setup context. */\nfunction initConnectorSetupContext(input: InitConnectorSetupContextInput): ConnectorSetupContext {\n const connectorName = input.options.connectorName ?? DEFAULT_CONNECTOR_NAME;\n const returnUrl = chatGptReturnUrl({ url: input.page.url() });\n return {\n page: input.page,\n connectorUrl: input.connectorUrl,\n options: input.options,\n connectorName,\n returnUrl,\n result: {\n connectorUrl: input.connectorUrl,\n completed: false,\n steps: [],\n warnings: [],\n },\n };\n}\n\n// --- connector/list-bridge-connector-summaries.ts ---\n\n/** Context for {@link collectConnectorSummaries}. */\ninterface CollectConnectorSummariesContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Number of connector buttons currently listed. */\n entryCount: number;\n}\n\n/** Collect unique connector summaries by opening each listed connector. */\nasync function collectConnectorSummaries(\n ctx: CollectConnectorSummariesContext,\n): Promise<ConnectorAppSummary[]> {\n const summaries: ConnectorAppSummary[] = [];\n const seen = new Set<string>();\n for (let index = 0; index < ctx.entryCount; index += 1) {\n appendUniqueSummary({\n summaries,\n seen,\n summary: await readConnectorSummaryAtIndex({ page: ctx.page, index }),\n });\n }\n return summaries;\n}\n\n/** Context for {@link listBridgeConnectorSummaries}. */\ninterface ListBridgeConnectorSummariesContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Enumerate all bridge connector apps listed in ChatGPT settings. */\nasync function listBridgeConnectorSummaries(\n ctx: ListBridgeConnectorSummariesContext,\n): Promise<ConnectorAppSummary[]> {\n await openConnectorList({ page: ctx.page });\n const entryCount = (await findBridgeConnectorButtons({ page: ctx.page })).length;\n const summaries = await collectConnectorSummaries({ page: ctx.page, entryCount });\n await openConnectorList({ page: ctx.page });\n return summaries;\n}\n\n// --- connector/open-advanced-settings.ts ---\n\n/** Open Advanced settings when the control is visible in the connectors panel. */\nasync function openAdvancedSettingsIfPresent(ctx: ConnectorSetupContext): Promise<void> {\n const opened = await clickFirstVisible({\n page: ctx.page,\n selectors: [\n 'button:has-text(\"Advanced settings\")',\n 'button:has-text(\"Advanced Settings\")',\n 'a:has-text(\"Advanced settings\")',\n '[role=\"tab\"]:has-text(\"Advanced\")',\n 'button:has-text(\"Advanced\")',\n ],\n timeout: 1_500,\n });\n if (opened) ctx.result.steps.push(\"Opened Advanced settings.\");\n}\n\n// --- connector/open-apps-or-connectors-panel.ts ---\n\n/** Open the Apps or Connectors panel inside ChatGPT settings. */\nasync function openAppsOrConnectorsPanel(ctx: ConnectorSetupContext): Promise<void> {\n const opened = await clickFirstVisible({\n page: ctx.page,\n selectors: [\n 'button:has-text(\"Apps\")',\n 'a:has-text(\"Apps\")',\n '[role=\"tab\"]:has-text(\"Apps\")',\n 'button:has-text(\"Connectors\")',\n 'a:has-text(\"Connectors\")',\n '[role=\"tab\"]:has-text(\"Connectors\")',\n ],\n timeout: 2_000,\n });\n if (opened) {\n ctx.result.steps.push(\"Opened Apps/Connectors settings.\");\n } else {\n ctx.result.warnings.push(\n \"Could not find Apps/Connectors in settings. Use Settings -> Apps manually.\",\n );\n }\n}\n\n// --- connector/open-chatgpt-settings.ts ---\n\n/** Open ChatGPT settings, preferring the Connectors deep link. */\nasync function openChatGptSettings(ctx: ConnectorSetupContext): Promise<void> {\n await ctx.page\n .goto(\"https://chatgpt.com/#settings/Connectors\", { waitUntil: \"domcontentloaded\" })\n .catch(() => {});\n await ctx.page.waitForTimeout(1_500);\n const settingsDialogOpen = await ctx.page\n .locator('[role=\"dialog\"]:has-text(\"Apps\"), [role=\"dialog\"]:has-text(\"Connectors\")')\n .first()\n .isVisible()\n .catch(() => false);\n if (settingsDialogOpen) {\n ctx.result.steps.push(\"Opened ChatGPT settings.\");\n return;\n }\n await openSettingsFromAccountMenu(ctx);\n}\n\n// --- connector/open-composer-connector-menu.ts ---\n\n/** Context for {@link openComposerPlusMenu}. */\ninterface OpenComposerPlusMenuContext {\n /** Connector setup context with page handle. */\n setup: ConnectorSetupContext;\n}\n\n/** Open the composer plus-menu for connector selection. */\nasync function openComposerPlusMenu(ctx: OpenComposerPlusMenuContext): Promise<boolean> {\n const plusButton = await firstVisible({\n page: ctx.setup.page,\n selectors: [\n '[data-testid=\"composer-plus-btn\"]',\n 'button[aria-label=\"Add files and more\"]',\n 'button[aria-label*=\"Add files\" i]',\n ],\n });\n if (!plusButton) return false;\n await plusButton.click({ timeout: 5_000, force: true });\n await ctx.setup.page.waitForTimeout(750);\n return true;\n}\n\n/** Open the composer plus-menu and choose the connector, including More submenu. */\nasync function openComposerConnectorMenu(ctx: ConnectorSetupContext): Promise<boolean> {\n if (!(await openComposerPlusMenu({ setup: ctx }))) return false;\n if (await clickConnectorMenuItem({ page: ctx.page, connectorName: ctx.connectorName }))\n return true;\n return clickConnectorFromMoreMenu(ctx);\n}\n\n// --- connector/open-connector-details-panel.ts ---\n\n/** Context for {@link openConnectorDetailsPanel}. */\ninterface OpenConnectorDetailsPanelContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n}\n\n/** Click an existing connector in the list and open its detail panel. */\nasync function openConnectorDetailsPanel(ctx: OpenConnectorDetailsPanelContext): Promise<boolean> {\n const button = await findConnectorButton({\n page: ctx.setup.page,\n connectorName: ctx.setup.connectorName,\n });\n if (!button) return false;\n await clickConnectorDetailsButton({ button, setup: ctx.setup });\n return true;\n}\n\n// --- connector/open-connector-list.ts ---\n\n/** Context for {@link openConnectorList}. */\ninterface OpenConnectorListContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Navigate to the connector list and back out of any open detail panel. */\nasync function openConnectorList(ctx: OpenConnectorListContext): Promise<void> {\n await ctx.page\n .goto(\"https://chatgpt.com/#settings/Connectors\", { waitUntil: \"domcontentloaded\" })\n .catch(() => {});\n await ctx.page.waitForTimeout(1_000);\n const backButton = await firstVisible({\n page: ctx.page,\n selectors: ['[role=\"dialog\"] button:has-text(\"Back\")'],\n });\n if (backButton) {\n await backButton.click({ timeout: 2_000, force: true }).catch(() => {});\n await ctx.page.waitForTimeout(750);\n }\n}\n\n// --- connector/open-create-connector-form.ts ---\n\n/** Open the connector/app creation form from settings. */\nasync function openCreateConnectorForm(ctx: ConnectorSetupContext): Promise<void> {\n const opened = await clickFirstVisible({\n page: ctx.page,\n selectors: [\n 'button:has-text(\"Create app\")',\n 'button:has-text(\"Create App\")',\n 'button:has-text(\"Create\")',\n 'button:has-text(\"Add connector\")',\n 'button:has-text(\"Add Connector\")',\n 'button:has-text(\"New app\")',\n 'button:has-text(\"New App\")',\n 'button:has-text(\"Connect\")',\n ],\n timeout: 2_000,\n });\n if (opened) {\n ctx.result.steps.push(\"Opened connector/app creation form.\");\n } else {\n ctx.result.warnings.push(\n \"Could not find Create app/Add connector. Use Settings -> Apps -> Advanced settings -> Create app manually.\",\n );\n }\n}\n\n// --- connector/open-existing-connector-details.ts ---\n\n/** Context for {@link readConnectorState}. */\ninterface ReadConnectorStateContext {\n /** Connector setup context with page and connector identifiers. */\n setup: ConnectorSetupContext;\n}\n\n/** Read the current open connector state for the desired connector. */\nfunction readConnectorState(ctx: ReadConnectorStateContext) {\n return readOpenConnectorState({\n page: ctx.setup.page,\n connectorName: ctx.setup.connectorName,\n connectorUrl: ctx.setup.connectorUrl,\n });\n}\n\n/** Open an existing connector's detail panel and classify its URL state. */\nasync function openExistingConnectorDetails(\n ctx: ConnectorSetupContext,\n): Promise<ExistingConnectorState> {\n const alreadyOpen = await readConnectorState({ setup: ctx });\n if (alreadyOpen !== \"missing\") return alreadyOpen;\n if (!(await openConnectorDetailsPanel({ setup: ctx }))) return \"missing\";\n return readConnectorState({ setup: ctx });\n}\n\n// --- connector/open-settings-from-account-menu.ts ---\n\n/** Open ChatGPT settings through the account menu when the deep link fails. */\nasync function openSettingsFromAccountMenu(ctx: ConnectorSetupContext): Promise<void> {\n await ctx.page.goto(\"https://chatgpt.com/\", { waitUntil: \"domcontentloaded\" }).catch(() => {});\n await ctx.page.waitForSelector(SELECTORS.promptInput, { timeout: 15_000 }).catch(() => {});\n if (\n !(await clickFirstVisible({\n page: ctx.page,\n selectors: SELECTORS.accountMenuButton,\n timeout: 2_000,\n }))\n ) {\n ctx.result.warnings.push(\"Could not find the ChatGPT profile/account menu.\");\n return;\n }\n ctx.result.steps.push(\"Opened ChatGPT account menu.\");\n await clickSettingsEntry({ setup: ctx });\n}\n\n// --- connector/read-connector-summary-at-index.ts ---\n\n/** Context for {@link readConnectorSummaryAtIndex}. */\ninterface ReadConnectorSummaryAtIndexContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Zero-based connector button index in the list. */\n index: number;\n}\n\n/** Open one connector by index and read its summary panel. */\nasync function readConnectorSummaryAtIndex(ctx: ReadConnectorSummaryAtIndexContext) {\n if (!(await clickConnectorListEntry({ page: ctx.page, index: ctx.index }))) return null;\n return readOpenConnectorSummary({ page: ctx.page });\n}\n\n// --- connector/read-open-connector-state.ts ---\n\n/** Context for {@link readOpenConnectorState}. */\ninterface ReadOpenConnectorStateContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Expected connector display name. */\n connectorName: string;\n /** Desired connector MCP URL. */\n connectorUrl: string;\n}\n\n/** Classify the open connector panel relative to the desired connector URL. */\nasync function readOpenConnectorState(\n ctx: ReadOpenConnectorStateContext,\n): Promise<ExistingConnectorState> {\n const text = await settingsDialogText({ page: ctx.page });\n if (!text.includes(ctx.connectorName) || !/\\b(URL|App Id|Version Id)\\b/i.test(text))\n return \"missing\";\n if (text.includes(ctx.connectorUrl)) return \"current\";\n if (/\\bURL\\s+https?:\\/\\//i.test(text)) return \"stale\";\n return \"unknown\";\n}\n\n// --- connector/read-open-connector-summary.ts ---\n\n/** Context for {@link parseConnectorSummaryLines}. */\ninterface ParseConnectorSummaryLinesContext {\n /** Dialog text split into trimmed lines. */\n lines: string[];\n}\n\n/** Parse connector name and metadata lines from an open settings dialog. */\nfunction parseConnectorSummaryLines(\n ctx: ParseConnectorSummaryLinesContext,\n): ConnectorAppSummary | null {\n const backIndex = ctx.lines.indexOf(\"Back\");\n const name = backIndex >= 0 ? (ctx.lines[backIndex + 1] ?? \"\") : \"\";\n if (!name.startsWith(BRIDGE_CONNECTOR_PREFIX)) return null;\n return {\n name,\n appId: valueAfterLine({ lines: ctx.lines, label: \"App Id\" }),\n url: valueAfterLine({ lines: ctx.lines, label: \"URL\" }),\n };\n}\n\n/** Context for {@link readOpenConnectorSummary}. */\ninterface ReadOpenConnectorSummaryContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Read connector details from the currently open settings dialog. */\nasync function readOpenConnectorSummary(\n ctx: ReadOpenConnectorSummaryContext,\n): Promise<ConnectorAppSummary | null> {\n const text = await ctx.page\n .locator('[role=\"dialog\"]')\n .last()\n .innerText()\n .catch(() => \"\");\n const lines = text\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean);\n return parseConnectorSummaryLines({ lines });\n}\n\n// --- connector/refresh-open-connector.ts ---\n\n/** Refresh the currently open connector tool schema when the button is visible. */\nasync function refreshOpenConnectorIfPresent(ctx: ConnectorSetupContext): Promise<boolean> {\n return clickFirstVisible({\n page: ctx.page,\n selectors: ['[role=\"dialog\"] button:has-text(\"Refresh\")'],\n timeout: 1_000,\n });\n}\n\n// --- connector/restore-after-connector-setup.ts ---\n\n/** Close settings and restore the pre-setup URL after a failed automatic setup. */\nasync function restoreAfterConnectorSetup(ctx: ConnectorSetupContext): Promise<void> {\n await closeSettingsDialogIfPresent(ctx);\n await restoreReturnUrlIfNeeded(ctx);\n}\n\n// --- connector/restore-return-url.ts ---\n\n/** Restore the pre-setup ChatGPT URL and wait for the composer when needed. */\nasync function restoreReturnUrlIfNeeded(ctx: ConnectorSetupContext): Promise<void> {\n if (ctx.returnUrl && chatGptReturnUrl({ url: ctx.page.url() }) !== ctx.returnUrl) {\n await ctx.page.goto(ctx.returnUrl, { waitUntil: \"domcontentloaded\" }).catch(() => {});\n }\n await ctx.page.waitForSelector(SELECTORS.promptInput, { timeout: 15_000 }).catch(() => {});\n}\n\n// --- connector/return-to-connector-list.ts ---\n\n/** Navigate back to the connector list from a detail panel when Back is visible. */\nasync function returnToConnectorListIfNeeded(ctx: ConnectorSetupContext): Promise<void> {\n const back = await firstVisible({\n page: ctx.page,\n selectors: ['[role=\"dialog\"] button:has-text(\"Back\")'],\n });\n if (back) {\n await back.click({ timeout: 2_000, force: true }).catch(() => {});\n await ctx.page.waitForTimeout(750);\n }\n}\n\n// --- connector/select-connector-after-setup.ts ---\n\n/** Select the connector in the composer after settings setup completes. */\nasync function selectConnectorAfterSetup(ctx: ConnectorSetupContext): Promise<void> {\n const selectedInComposer = await selectConnectorInComposer(ctx);\n if (selectedInComposer) {\n ctx.result.steps.push(\"Selected the connector in the composer.\");\n } else {\n ctx.result.warnings.push(\n \"Connector is configured, but the composer menu did not expose it for automatic selection.\",\n );\n }\n}\n\n// --- connector/select-connector-in-composer.ts ---\n\n/** Select the configured connector in the ChatGPT composer plus-menu. */\nasync function selectConnectorInComposer(ctx: ConnectorSetupContext): Promise<boolean> {\n await closeSettingsDialogIfPresent(ctx);\n await restoreReturnUrlIfNeeded(ctx);\n await ctx.page.keyboard.press(\"Escape\").catch(() => {});\n return ensureComposerConnectorSelected(ctx);\n}\n\n// --- connector/select-no-authentication.ts ---\n\n/** Select the no-authentication option in the connector form when present. */\nasync function selectNoAuthenticationIfPresent(ctx: ConnectorSetupContext): Promise<boolean> {\n const authSelect = ctx.page.locator(\"select#custom-connector-auth\").first();\n if ((await authSelect.count()) > 0 && (await authSelect.isVisible().catch(() => false))) {\n await authSelect.selectOption(\"NONE\");\n await authSelect.dispatchEvent(\"change\").catch(() => {});\n return true;\n }\n return clickFirstVisible({\n page: ctx.page,\n selectors: [\n 'button:has-text(\"No authentication\")',\n 'button:has-text(\"No Authentication\")',\n 'label:has-text(\"No authentication\")',\n 'label:has-text(\"No Authentication\")',\n '[role=\"radio\"]:has-text(\"No authentication\")',\n '[role=\"radio\"]:has-text(\"No Auth\")',\n '[role=\"option\"]:has-text(\"No authentication\")',\n '[role=\"option\"]:has-text(\"No Auth\")',\n 'button:has-text(\"No Auth\")',\n 'button:has-text(\"None\")',\n ],\n timeout: 1_000,\n });\n}\n\n// --- connector/settings-dialog-text.ts ---\n\n/** Context for {@link settingsDialogText}. */\ninterface SettingsDialogTextContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Read normalized text from the last open settings dialog. */\nasync function settingsDialogText(ctx: SettingsDialogTextContext): Promise<string> {\n return normalizeDisplayText({\n value: await ctx.page\n .locator('[role=\"dialog\"]')\n .last()\n .innerText()\n .catch(() => \"\"),\n });\n}\n\n// --- connector/setup-connector.ts ---\n\n/** Best-effort ChatGPT Developer Mode connector setup through the browser UI. */\nasync function setupMcpConnectorInChatGpt(\n page: Page,\n connectorUrl: string,\n options: ConnectorSetupOptions = {},\n): Promise<ConnectorSetupResult> {\n return executeConnectorSetup(initConnectorSetupContext({ page, connectorUrl, options }));\n}\n\n// --- connector/submit-connector-form.ts ---\n\n/** Context for {@link connectorFormStillOpen}. */\ninterface ConnectorFormStillOpenContext {\n /** Connector setup context with page handle. */\n setup: ConnectorSetupContext;\n}\n\n/** True when the connector URL field is still visible after submit. */\nasync function connectorFormStillOpen(ctx: ConnectorFormStillOpenContext): Promise<boolean> {\n return ctx.setup.page\n .locator('input[name=\"custom-connector-url\"], #custom-connector-url')\n .first()\n .isVisible()\n .catch(() => false);\n}\n\n/** Context for {@link markConnectorSubmitCompleted}. */\ninterface MarkConnectorSubmitCompletedContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n}\n\n/** Mark connector setup complete and select the connector in the composer. */\nasync function markConnectorSubmitCompleted(\n ctx: MarkConnectorSubmitCompletedContext,\n): Promise<void> {\n ctx.setup.result.completed = true;\n ctx.setup.result.steps.push(\"Submitted the connector form.\");\n await selectConnectorAfterSetup(ctx.setup);\n}\n\n/** Context for {@link warnConnectorSubmitIncomplete}. */\ninterface WarnConnectorSubmitIncompleteContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n}\n\n/** Warn when the connector form remains open after submit. */\nasync function warnConnectorSubmitIncomplete(\n ctx: WarnConnectorSubmitIncompleteContext,\n): Promise<void> {\n const appVisible = await waitForConnectorButton({\n page: ctx.setup.page,\n connectorName: ctx.setup.connectorName,\n timeoutMs: 20_000,\n });\n const formStillOpen = await connectorFormStillOpen({ setup: ctx.setup });\n if (formStillOpen && !appVisible) {\n ctx.setup.result.warnings.push(\n \"Connector form is still open after submit. Check the visible validation message in ChatGPT settings.\",\n );\n return;\n }\n await markConnectorSubmitCompleted({ setup: ctx.setup });\n}\n\n/** Submit the connector creation form and finalize the setup result. */\nasync function submitConnectorForm(ctx: ConnectorSetupContext): Promise<void> {\n const submitted = await clickFirstVisible({\n page: ctx.page,\n selectors: [\n 'button:has-text(\"Create\")',\n 'button:has-text(\"Save\")',\n 'button:has-text(\"Add\")',\n 'button:has-text(\"Connect\")',\n ],\n timeout: 2_000,\n });\n if (!submitted) {\n ctx.result.warnings.push(\n \"Connector form was filled, but no Create/Save/Add button was visible or enabled.\",\n );\n return;\n }\n await warnConnectorSubmitIncomplete({ setup: ctx });\n}\n\n// --- connector/try-finalize-existing-connector.ts ---\n\n/** Context for {@link finalizeIfCurrentConnector}. */\ninterface FinalizeIfCurrentConnectorContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n}\n\n/** Open existing connector details and finalize when the URL already matches. */\nasync function finalizeIfCurrentConnector(\n ctx: FinalizeIfCurrentConnectorContext,\n): Promise<boolean> {\n const existing = await openExistingConnectorDetails(ctx.setup);\n if (existing !== \"current\") return false;\n await finalizeCurrentConnector(ctx.setup);\n return true;\n}\n\n/** Context for {@link tryFinalizeExistingConnector}. */\ninterface TryFinalizeExistingConnectorContext {\n /** Connector setup context with page and result accumulator. */\n setup: ConnectorSetupContext;\n /** Whether duplicate cleanup already found the current connector. */\n hasCurrentConnector: boolean;\n}\n\n/** Attempt to finalize when an existing connector already matches the desired URL. */\nasync function tryFinalizeExistingConnector(\n ctx: TryFinalizeExistingConnectorContext,\n): Promise<boolean> {\n if (ctx.hasCurrentConnector && (await finalizeIfCurrentConnector({ setup: ctx.setup })))\n return true;\n return finalizeIfCurrentConnector({ setup: ctx.setup });\n}\n\n// --- conversation/capture-all-messages.ts ---\n\n/** Extract all messages from the current conversation in DOM order. */\nasync function captureAllMessages(page: Page): Promise<Array<{ role: string; content: string }>> {\n return extractAllMessages(page, { conversationId: conversationIdFromPage({ page }) });\n}\n\n// --- conversation/capture-last-response.ts ---\n\nfunction sanitizeCapturedText(value: string): string {\n return value\n .replace(/\\s*\\[object Object\\]\\s*/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** Extract the text content of the last assistant response. */\nasync function captureLastResponse(page: Page): Promise<string> {\n const { text } = await extractAssistantContent(page, {\n conversationId: conversationIdFromPage({ page }),\n });\n const cleaned = sanitizeCapturedText(text);\n if (cleaned && !/\\[object Object\\]/.test(text)) return cleaned;\n\n const fallback = await page\n .locator(SELECTORS.lastResponse)\n .last()\n .innerText()\n .catch(() => \"\");\n return sanitizeCapturedText(fallback) || cleaned;\n}\n\n// --- conversation/conversation-id-from-page.ts ---\n\n/** Context for {@link conversationIdFromPage}. */\ninterface ConversationIdFromPageContext {\n /** Playwright page handle whose URL may contain a conversation id. */\n page: Page;\n}\n\n/** Extract the `/c/{id}` segment from the current page URL, or `\"current\"`. */\nfunction conversationIdFromPage(ctx: ConversationIdFromPageContext): string {\n const match = /\\/c\\/([^/?#]+)/.exec(ctx.page.url());\n return match?.[1] ?? \"current\";\n}\n\n// --- conversation/count-assistant-responses.ts ---\n\n/** Count assistant responses currently rendered in the conversation. */\nasync function countAssistantResponses(page: Page): Promise<number> {\n return page.locator(SELECTORS.responseBlock).count();\n}\n\n// --- conversation/navigate-to-conversation.ts ---\n\n/** Wait until ChatGPT is not actively generating before navigation or send. */\nasync function waitForGenerationIdle(page: Page, timeoutMs = 120_000): Promise<void> {\n const startedAt = Date.now();\n while (Date.now() - startedAt < timeoutMs) {\n const streaming = await isStreamingVisible({ page }).catch(() => false);\n if (!streaming) {\n await page.waitForTimeout(400).catch(() => {});\n if (!(await isStreamingVisible({ page }).catch(() => false))) return;\n }\n await page.waitForTimeout(500).catch(() => {});\n }\n throw new Error(\"Timed out waiting for ChatGPT to finish generating.\");\n}\n\n/** Navigate to a specific conversation by URL. Skips reload when already on thread. */\nasync function navigateToConversation(page: Page, url: string): Promise<void> {\n const targetUrl = conversationUrlFromIdOrUrl(url);\n if (isSameChatGptConversation(page.url(), targetUrl)) {\n await page\n .waitForSelector(\"#prompt-textarea, [contenteditable]\", { timeout: 30_000 })\n .catch(() => {});\n return;\n }\n await waitForGenerationIdle(page);\n await page.goto(targetUrl);\n await page.waitForSelector(\"#prompt-textarea, [contenteditable]\", { timeout: 30_000 });\n}\n\n// --- conversation/new-conversation.ts ---\n\n/** Start a new ChatGPT conversation. */\nasync function newConversation(page: Page): Promise<void> {\n await page.goto(\"https://chatgpt.com/\");\n await page.waitForSelector(\"#prompt-textarea, [contenteditable]\", { timeout: 30_000 });\n}\n\n// --- conversation/parse-sidebar-link.ts ---\n\n/** A sidebar conversation entry parsed from a nav link. */\ninterface SidebarConversationEntry {\n /** Conversation id from the URL path segment. */\n id: string;\n /** Visible title text from the sidebar link. */\n title: string;\n /** Absolute ChatGPT URL for the conversation. */\n url: string;\n}\n\n/** Context for {@link parseSidebarLink}. */\ninterface ParseSidebarLinkContext {\n /** Sidebar conversation link locator. */\n link: Locator;\n}\n\n/** Parse one sidebar link into a conversation entry, or null when incomplete. */\nasync function parseSidebarLink(\n ctx: ParseSidebarLinkContext,\n): Promise<SidebarConversationEntry | null> {\n const href = await ctx.link.getAttribute(\"href\");\n const title = await ctx.link.innerText();\n if (!href || !title) return null;\n const id = href.split(\"/\").pop() ?? \"\";\n return { id, title: title.trim(), url: `https://chatgpt.com${href}` };\n}\n\n// --- conversation/read-sidebar-conversations.ts ---\n\n/** Read the conversation list from the sidebar. */\nasync function readSidebarConversations(\n page: Page,\n): Promise<Array<{ id: string; title: string; url: string }>> {\n const links = await page.locator(SELECTORS.sidebarConversation).all();\n const conversations: Array<{ id: string; title: string; url: string }> = [];\n for (const link of links) {\n const entry = await parseSidebarLink({ link });\n if (entry) conversations.push(entry);\n }\n return conversations;\n}\n\n// --- dom/click-first-visible.ts ---\n\n/** Context for {@link clickFirstVisible}. */\ninterface ClickFirstVisibleContext {\n /** Playwright page handle to search within. */\n page: Page;\n /** Candidate selectors to click in order. */\n selectors: readonly string[];\n /** Per-selector visibility wait timeout in milliseconds. */\n timeout?: number;\n}\n\n/** Click the first visible element matching any selector; return whether a click succeeded. */\nasync function clickFirstVisible(ctx: ClickFirstVisibleContext): Promise<boolean> {\n const timeout = ctx.timeout ?? 1_000;\n for (const selector of ctx.selectors) {\n const locator = ctx.page.locator(selector).first();\n await locator.waitFor({ state: \"visible\", timeout }).catch(() => {});\n if ((await locator.count()) > 0 && (await locator.isVisible().catch(() => false))) {\n try {\n await locator.click({ timeout });\n return true;\n } catch {\n try {\n await locator.click({ timeout, force: true });\n return true;\n } catch {\n // both click attempts failed; fall through to the next candidate locator\n }\n }\n }\n }\n return false;\n}\n\n// --- dom/fill-first-visible.ts ---\n\n/** Context for {@link fillFirstVisible}. */\ninterface FillFirstVisibleContext {\n /** Playwright page handle to search within. */\n page: import(\"playwright\").Page;\n /** Candidate field selectors to fill in order. */\n selectors: readonly string[];\n /** Value to write into the first visible field. */\n value: string;\n}\n\n/** Context for {@link fillVisibleField}. */\ninterface FillVisibleFieldContext {\n /** Visible input locator to fill. */\n field: Locator;\n /** Value to write into the field. */\n value: string;\n}\n\n/** Fill one visible field and dispatch input/change events. */\nasync function fillVisibleField(ctx: FillVisibleFieldContext): Promise<void> {\n await ctx.field.fill(ctx.value);\n await ctx.field.dispatchEvent(\"input\").catch(() => {});\n await ctx.field.dispatchEvent(\"change\").catch(() => {});\n}\n\n/** Fill the first visible input matching any selector; return whether a field was filled. */\nasync function fillFirstVisible(ctx: FillFirstVisibleContext): Promise<boolean> {\n const field = await firstVisible({ page: ctx.page, selectors: ctx.selectors });\n if (!field) return false;\n await fillVisibleField({ field, value: ctx.value });\n return true;\n}\n\n// --- dom/first-visible-in.ts ---\n\n/** Context for {@link firstVisibleIn}. */\ninterface FirstVisibleInContext {\n /** Parent locator to search within. */\n parent: Locator;\n /** Candidate selectors to probe in order. */\n selectors: readonly string[];\n}\n\n/** Return the first visible child locator matching any selector, or null. */\nasync function firstVisibleIn(ctx: FirstVisibleInContext): Promise<Locator | null> {\n for (const selector of ctx.selectors) {\n const locator = ctx.parent.locator(selector).first();\n if ((await locator.count()) > 0 && (await locator.isVisible().catch(() => false))) {\n return locator;\n }\n }\n return null;\n}\n\n// --- dom/first-visible.ts ---\n\n/** Context for {@link firstVisible}. */\ninterface FirstVisibleContext {\n /** Playwright page handle to search within. */\n page: Page;\n /** Candidate selectors to probe in order. */\n selectors: readonly string[];\n}\n\n/** Return the first visible locator matching any selector, or null. */\nasync function firstVisible(ctx: FirstVisibleContext): Promise<Locator | null> {\n for (const selector of ctx.selectors) {\n const locator = ctx.page.locator(selector).first();\n if ((await locator.count()) > 0 && (await locator.isVisible().catch(() => false))) {\n return locator;\n }\n }\n return null;\n}\n\n// --- dom/normalize-display-text.ts ---\n/** Context for {@link normalizeDisplayText}. */\ninterface NormalizeDisplayTextContext {\n /** Raw text pulled from the ChatGPT DOM. */\n value: string;\n}\n\n/** Collapse whitespace and strip \"(current|selected)\" markers from UI labels. */\nfunction normalizeDisplayText(ctx: NormalizeDisplayTextContext): string {\n return ctx.value\n .replace(/\\s+/g, \" \")\n .replace(/\\b(current|selected)\\b/gi, \"\")\n .trim();\n}\n\n// --- dom/normalize-model-query.ts ---\n/** Context for {@link normalizeModelQuery}. */\ninterface NormalizeModelQueryContext {\n /** User-supplied or DOM-derived model label or id. */\n value: string;\n}\n\n/** Normalize a model query string for fuzzy matching against menu items. */\nfunction normalizeModelQuery(ctx: NormalizeModelQueryContext): string {\n return ctx.value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9.]+/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n// --- guestSessionError.ts ---\n// GuestSessionError exported at top of file.\n\n// --- model/click-model-and-detect.ts ---\n\n/** Context for {@link clickModelAndDetect}. */\ninterface ClickModelAndDetectContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Model menu item to click. */\n item: Locator;\n}\n\n/** Click a model item, wait for the menu to close, and return the detected model. */\nasync function clickModelAndDetect(ctx: ClickModelAndDetectContext): Promise<string> {\n await ctx.item.click();\n await ctx.page\n .locator(SELECTORS.openMenu)\n .waitFor({ state: \"hidden\", timeout: 5_000 })\n .catch(() => {});\n await ctx.page.waitForTimeout(500);\n return detectCurrentModel(ctx.page);\n}\n\n// --- model/collect-models-from-items.ts ---\n\n/** Context for {@link collectModelsFromItems}. */\ninterface CollectModelsFromItemsContext {\n /** Model menu item locators to parse. */\n items: Locator[];\n}\n\n/** Parse menu items into a deduplicated model option list. */\nasync function collectModelsFromItems(ctx: CollectModelsFromItemsContext): Promise<ModelOption[]> {\n const models: ModelOption[] = [];\n for (const item of ctx.items) {\n const option = await parseModelMenuItem({ item });\n if (option && !models.some((model) => model.id === option.id && model.label === option.label)) {\n models.push(option);\n }\n }\n return models;\n}\n\n/** Context for {@link closeModelMenu}. */\ninterface CloseModelMenuContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Dismiss the open model menu with Escape. */\nasync function closeModelMenu(ctx: CloseModelMenuContext): Promise<void> {\n await ctx.page.keyboard.press(\"Escape\").catch(() => {});\n}\n\n// --- model/detect-checked-model-from-menu.ts ---\n\n/** Context for {@link detectCheckedModelFromMenuOnce}. */\ninterface DetectCheckedModelFromMenuOnceContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Try once to read the checked model from the model menu. */\nasync function detectCheckedModelFromMenuOnce(\n ctx: DetectCheckedModelFromMenuOnceContext,\n): Promise<string | null> {\n try {\n await openModelMenu({ page: ctx.page });\n const checkedModel = await readCheckedModelFromOpenMenu({ page: ctx.page });\n await ctx.page.keyboard.press(\"Escape\").catch(() => {});\n return checkedModel;\n } catch {\n await ctx.page.keyboard.press(\"Escape\").catch(() => {});\n return null;\n }\n}\n\n/** Context for {@link detectCheckedModelFromMenu}. */\ninterface DetectCheckedModelFromMenuContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Retry opening the model menu until a checked model label is found. */\nasync function detectCheckedModelFromMenu(\n ctx: DetectCheckedModelFromMenuContext,\n): Promise<string | null> {\n for (let attempt = 0; attempt < 4; attempt += 1) {\n const checkedModel = await detectCheckedModelFromMenuOnce({ page: ctx.page });\n if (checkedModel) return checkedModel;\n await ctx.page.waitForTimeout(750);\n }\n return null;\n}\n\n// --- model/detect-current-model.ts ---\n\n/** Detect the currently selected ChatGPT model from the page DOM. */\nasync function detectCurrentModel(page: Page): Promise<string> {\n try {\n const fromDom = await readCheckedModelFromDom({ page });\n if (fromDom) return fromDom;\n const fromTrigger = await readModelFromTrigger({ page });\n if (fromTrigger) return fromTrigger;\n const fromMenu = await detectCheckedModelFromMenu({ page });\n return fromMenu ?? \"ChatGPT\";\n } catch {\n return \"ChatGPT\";\n }\n}\n\n// --- model/find-model-menu-match.ts ---\n\n/** Context for {@link findModelMenuMatch}. */\ninterface FindModelMenuMatchContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Normalized model search query. */\n normalizedQuery: string;\n}\n\n/** Find the first matching model menu item, tracking a fuzzy fallback. */\nasync function findModelMenuMatch(ctx: FindModelMenuMatchContext): Promise<Locator | null> {\n const items = await modelMenuItems(ctx.page);\n let fallback: Locator | null = null;\n for (const item of items) {\n const result = await modelItemMatchesQuery({ item, normalizedQuery: ctx.normalizedQuery });\n if (result.matched) return item;\n if (!fallback && result.fallback) fallback = result.fallback;\n }\n return fallback;\n}\n\n// --- model/is-likely-model-label.ts ---\n/** True when a string looks like a real ChatGPT model name (vs. arbitrary UI text). */\nfunction isLikelyModelLabel(value: string): boolean {\n return /\\b(gpt|chatgpt|o[1-9]|claude|glm)\\b/i.test(value);\n}\n\n// --- model/is-selected-model-item.ts ---\n\n/** Context for {@link isSelectedModelItem}. */\ninterface IsSelectedModelItemContext {\n /** Model menu item locator. */\n item: Locator;\n}\n\n/** True when the menu item represents the currently selected model. */\nasync function isSelectedModelItem(ctx: IsSelectedModelItemContext): Promise<boolean> {\n const ariaChecked = await ctx.item.getAttribute(\"aria-checked\").catch(() => null);\n if (ariaChecked === \"true\") return true;\n const dataState = await ctx.item.getAttribute(\"data-state\").catch(() => null);\n return dataState === \"checked\";\n}\n\n// --- model/list-available-models.ts ---\n\n/** Read available models from ChatGPT's model menu. */\nasync function listAvailableModels(page: Page) {\n await openModelMenu({ page });\n const items = await modelMenuItems(page);\n const models = await collectModelsFromItems({ items });\n await closeModelMenu({ page });\n return models;\n}\n\n// --- model/model-item-matches-query.ts ---\n\n/** Context for {@link modelItemMatchesQuery}. */\ninterface ModelItemMatchesQueryContext {\n /** Model menu item locator. */\n item: Locator;\n /** Normalized model search query. */\n normalizedQuery: string;\n}\n\n/** Result of matching a model menu item against a query. */\ninterface ModelItemMatchResult {\n /** Whether the item exactly or partially matches the query. */\n matched: boolean;\n /** Locator to use as a fuzzy fallback when no exact match exists. */\n fallback: Locator | null;\n}\n\n/** Context for {@link buildModelItemMatchResult}. */\ninterface BuildModelItemMatchResultContext {\n /** Model menu item locator. */\n item: Locator;\n /** Human-readable model label. */\n label: string;\n /** Normalized model search query. */\n normalizedQuery: string;\n /** Searchable normalized label/id string. */\n searchable: string;\n}\n\n/** Build a match result from label and searchable text. */\nfunction buildModelItemMatchResult(ctx: BuildModelItemMatchResultContext): ModelItemMatchResult {\n if (ctx.searchable === ctx.normalizedQuery || ctx.searchable.includes(ctx.normalizedQuery)) {\n return { matched: true, fallback: null };\n }\n const fallback = ctx.normalizedQuery.includes(normalizeModelQuery({ value: ctx.label }))\n ? ctx.item\n : null;\n return { matched: false, fallback };\n}\n\n/** Test whether a menu item matches a normalized model query. */\nasync function modelItemMatchesQuery(\n ctx: ModelItemMatchesQueryContext,\n): Promise<ModelItemMatchResult> {\n const label = await readModelItemLabel({ item: ctx.item });\n const id = await readModelItemId({ item: ctx.item });\n const searchable = normalizeModelQuery({ value: `${label} ${id}` });\n if (!label || !isLikelyModelLabel(label)) return { matched: false, fallback: null };\n return buildModelItemMatchResult({\n item: ctx.item,\n label,\n normalizedQuery: ctx.normalizedQuery,\n searchable,\n });\n}\n\n// --- model/model-labels.config.ts ---\n/** Known model data-testid suffixes to human-readable names. */\nconst MODEL_LABELS: Record<string, string> = {\n \"gpt-5-3\": \"GPT-5.3 Instant\",\n \"gpt-5-5-thinking\": \"GPT-5.5 Thinking\",\n \"gpt-5-5-pro\": \"GPT-5.5 Pro\",\n \"gpt-5-2\": \"GPT-5.2\",\n \"gpt-5-2-chat-latest\": \"GPT-5.2 Chat\",\n \"gpt-5-1\": \"GPT-5.1\",\n \"gpt-5-1-chat-latest\": \"GPT-5.1 Chat\",\n \"gpt-5\": \"GPT-5\",\n \"gpt-4o\": \"GPT-4o\",\n \"gpt-4o-mini\": \"GPT-4o Mini\",\n \"gpt-4-1\": \"GPT-4.1\",\n \"gpt-4\": \"GPT-4\",\n o1: \"o1\",\n \"o1-pro\": \"o1 Pro\",\n \"o1-mini\": \"o1 Mini\",\n \"o3-mini\": \"o3 Mini\",\n};\n\n// --- model/model-menu-items.ts ---\n\n/** Return all model menu item locators from the open model switcher menu. */\nasync function modelMenuItems(page: Page): Promise<Locator[]> {\n return page\n .locator(\n [\n '[role=\"menu\"] [role=\"menuitem\"]',\n '[role=\"menu\"] [role=\"menuitemradio\"]',\n '[data-radix-menu-content] [role=\"menuitem\"]',\n '[data-radix-menu-content] [role=\"menuitemradio\"]',\n '[role=\"menu\"] [data-testid^=\"model-switcher-\"]',\n '[data-radix-menu-content] [data-testid^=\"model-switcher-\"]',\n ].join(\", \"),\n )\n .all();\n}\n\n// --- model/open-model-menu.ts ---\n\n/** Context for {@link clickModelTrigger}. */\ninterface ClickModelTriggerContext {\n /** Model switcher trigger locator. */\n trigger: NonNullable<Awaited<ReturnType<typeof firstVisible>>>;\n}\n\n/** Click the model switcher trigger, forcing if needed. */\nasync function clickModelTrigger(ctx: ClickModelTriggerContext): Promise<void> {\n try {\n await ctx.trigger.click({ timeout: 5_000 });\n } catch {\n await ctx.trigger.click({ timeout: 5_000, force: true });\n }\n}\n\n/** Context for {@link openModelMenu}. */\ninterface OpenModelMenuContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Open the ChatGPT model switcher dropdown menu. */\nasync function openModelMenu(ctx: OpenModelMenuContext): Promise<void> {\n await ctx.page\n .locator(SELECTORS.modelTrigger.join(\", \"))\n .first()\n .waitFor({ state: \"visible\", timeout: 5_000 })\n .catch(() => {});\n const trigger = await firstVisible({ page: ctx.page, selectors: SELECTORS.modelTrigger });\n if (!trigger) throw new Error(\"Could not find ChatGPT model switcher button.\");\n await clickModelTrigger({ trigger });\n await ctx.page.locator(SELECTORS.openMenu).first().waitFor({ state: \"visible\", timeout: 5_000 });\n}\n\n// --- model/parse-model-menu-item.ts ---\n\n/** Context for {@link parseModelMenuItem}. */\ninterface ParseModelMenuItemContext {\n /** Model menu item locator. */\n item: Locator;\n}\n\n/** Parse one model menu item into a {@link ModelOption}, or null when not a model. */\nasync function parseModelMenuItem(ctx: ParseModelMenuItemContext): Promise<ModelOption | null> {\n const label = await readModelItemLabel({ item: ctx.item });\n if (!label || !isLikelyModelLabel(label)) return null;\n const id = await readModelItemId({ item: ctx.item });\n const selected = await isSelectedModelItem({ item: ctx.item });\n return { id, label, selected };\n}\n\n// --- model/read-checked-model-from-dom.ts ---\n\n/** Context for {@link readCheckedModelFromDom}. */\ninterface ReadCheckedModelFromDomContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Read the checked model from aria-checked switcher items in the DOM. */\nasync function readCheckedModelFromDom(\n ctx: ReadCheckedModelFromDomContext,\n): Promise<string | null> {\n const checked = ctx.page.locator('[data-testid^=\"model-switcher-\"][aria-checked=\"true\"]').first();\n if ((await checked.count()) > 0) {\n return readModelItemLabel({ item: checked });\n }\n return null;\n}\n\n// --- model/read-checked-model-from-open-menu.ts ---\n\n/** Context for {@link readCheckedModelFromOpenMenu}. */\ninterface ReadCheckedModelFromOpenMenuContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Read the label of the checked model item from an already-open menu. */\nasync function readCheckedModelFromOpenMenu(\n ctx: ReadCheckedModelFromOpenMenuContext,\n): Promise<string | null> {\n const items = await modelMenuItems(ctx.page);\n for (const item of items) {\n if (await isSelectedModelItem({ item })) {\n const label = await readModelItemLabel({ item });\n if (label) return label;\n }\n }\n return null;\n}\n\n// --- model/read-likely-aria-model-label.ts ---\n\n/** Context for {@link readLikelyAriaModelLabel}. */\ninterface ReadLikelyAriaModelLabelContext {\n /** Model switcher trigger locator. */\n trigger: Locator;\n}\n\n/** Read a model label from the trigger aria-label when it looks valid. */\nasync function readLikelyAriaModelLabel(\n ctx: ReadLikelyAriaModelLabelContext,\n): Promise<string | null> {\n const ariaLabel = await ctx.trigger.getAttribute(\"aria-label\").catch(() => null);\n return ariaLabel && isLikelyModelLabel(ariaLabel) ? ariaLabel.trim() : null;\n}\n\n// --- model/read-likely-model-line.ts ---\n\n/** Context for {@link readLikelyModelLine}. */\ninterface ReadLikelyModelLineContext {\n /** Normalized trigger button text. */\n text: string;\n}\n\n/** Return the first line in trigger text that looks like a model label. */\nfunction readLikelyModelLine(ctx: ReadLikelyModelLineContext): string | null {\n return ctx.text.split(\"\\n\").find((part) => isLikelyModelLabel(part)) ?? null;\n}\n\n// --- model/read-model-from-trigger.ts ---\n\n/** Context for {@link readModelFromTrigger}. */\ninterface ReadModelFromTriggerContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Read the current model label from the model switcher trigger button. */\nasync function readModelFromTrigger(ctx: ReadModelFromTriggerContext): Promise<string | null> {\n const trigger = await firstVisible({ page: ctx.page, selectors: SELECTORS.modelTrigger });\n if (!trigger) return null;\n const line = readLikelyModelLine({\n text: normalizeDisplayText({ value: await trigger.innerText().catch(() => \"\") }),\n });\n if (line) return line;\n return readLikelyAriaModelLabel({ trigger });\n}\n\n// --- model/read-model-item-id.ts ---\n\n/** Context for {@link readModelItemId}. */\ninterface ReadModelItemIdContext {\n /** Model menu item locator. */\n item: Locator;\n}\n\n/** Derive a stable model id from a menu item's test id or label. */\nasync function readModelItemId(ctx: ReadModelItemIdContext): Promise<string> {\n const testId = await ctx.item.getAttribute(\"data-testid\").catch(() => null);\n if (testId?.startsWith(\"model-switcher-\")) return testId.replace(\"model-switcher-\", \"\");\n const label = await readModelItemLabel({ item: ctx.item });\n return normalizeModelQuery({ value: label }).replace(/\\s+/g, \"-\");\n}\n\n// --- model/read-model-item-label.ts ---\n\n/** Context for {@link readModelItemLabel}. */\ninterface ReadModelItemLabelContext {\n /** Model menu item locator. */\n item: Locator;\n}\n\n/** Read the human-readable label for a model menu item. */\nasync function readModelItemLabel(ctx: ReadModelItemLabelContext): Promise<string> {\n const testId = await ctx.item.getAttribute(\"data-testid\").catch(() => null);\n if (testId?.startsWith(\"model-switcher-\")) {\n const key = testId.replace(\"model-switcher-\", \"\");\n if (MODEL_LABELS[key]) return MODEL_LABELS[key];\n }\n return normalizeDisplayText({ value: await ctx.item.innerText().catch(() => \"\") });\n}\n\n// --- model/select-model.ts ---\n\n/** Context for {@link selectModelOrThrow}. */\ninterface SelectModelOrThrowContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Original user-supplied model query for error messages. */\n query: string;\n /** Normalized model search query. */\n normalizedQuery: string;\n}\n\n/** Open the model menu, click a match, or throw when none is found. */\nasync function selectModelOrThrow(ctx: SelectModelOrThrowContext): Promise<string> {\n await openModelMenu({ page: ctx.page });\n const match = await findModelMenuMatch({ page: ctx.page, normalizedQuery: ctx.normalizedQuery });\n if (match) return clickModelAndDetect({ page: ctx.page, item: match });\n await closeModelMenu({ page: ctx.page });\n throw new Error(`No model matched \"${ctx.query}\". Run /model to list available browser models.`);\n}\n\n/** Select a ChatGPT model by visible label, data-testid suffix, or fuzzy query. */\nasync function selectModel(page: Page, query: string): Promise<string> {\n const normalizedQuery = normalizeModelQuery({ value: query });\n if (!normalizedQuery) throw new Error(\"Model name is required.\");\n return selectModelOrThrow({ page, query, normalizedQuery });\n}\n\n// --- prompt/click-send-button.ts ---\n\n/** Context for {@link clickSendButton}. */\ninterface ClickSendButtonContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Click the send button or fall back to pressing Enter. */\nasync function clickSendButton(ctx: ClickSendButtonContext): Promise<void> {\n const sendBtn = ctx.page.locator(SELECTORS.sendButton).first();\n try {\n await sendBtn.waitFor({ state: \"visible\", timeout: 5_000 });\n await sendBtn.click();\n } catch {\n await ctx.page.keyboard.press(\"Enter\");\n }\n}\n\n// --- prompt/composer-clears-once.ts ---\n\n/** Context for {@link composerClearsOnce}. */\ninterface ComposerClearsOnceContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Poll the composer once and return true when it has emptied. */\nasync function composerClearsOnce(ctx: ComposerClearsOnceContext): Promise<boolean> {\n const composerText = await readComposerText({ page: ctx.page });\n return composerText === \"\";\n}\n\n// --- prompt/composer-clears.ts ---\n\n/** Context for {@link composerClears}. */\ninterface ComposerClearsContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/**\n * Poll the composer until it empties, signalling the prompt was actually sent.\n *\n * Returns false once the poll budget is spent so the caller can re-send.\n */\nasync function composerClears(ctx: ComposerClearsContext): Promise<boolean> {\n for (let poll = 0; poll < 10; poll += 1) {\n if (await composerClearsOnce({ page: ctx.page })) return true;\n await ctx.page.waitForTimeout(500);\n }\n return false;\n}\n\n// --- prompt/inject-prompt.ts ---\n\n/**\n * Type a prompt into ChatGPT's input field, send it, and confirm it actually left\n * the composer before returning.\n */\nasync function injectPrompt(page: Page, text: string): Promise<void> {\n await page.bringToFront().catch(() => {});\n await waitForGenerationIdle(page);\n await runInjectPromptAttempts({ page, text });\n}\n\n// --- prompt/read-composer-text.ts ---\n\n/** Context for {@link readComposerText}. */\ninterface ReadComposerTextContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Read the current trimmed text from the ChatGPT composer. */\nasync function readComposerText(ctx: ReadComposerTextContext): Promise<string> {\n const text = await ctx.page.evaluate(() =>\n (document.querySelector<HTMLElement>(\"#prompt-textarea\")?.innerText ?? \"\").trim(),\n );\n return text ?? \"\";\n}\n\n// --- prompt/run-inject-prompt-attempts.ts ---\n\n/** Context for {@link runInjectPromptAttempts}. */\ninterface RunInjectPromptAttemptsContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Prompt text to inject into the composer. */\n text: string;\n}\n\n/** Retry sending until the composer clears or attempts are exhausted. */\nasync function runInjectPromptAttempts(ctx: RunInjectPromptAttemptsContext): Promise<void> {\n const input = ctx.page.locator(SELECTORS.promptInput).first();\n for (let attempt = 0; attempt < 3; attempt += 1) {\n if (await submitPromptAttempt({ page: ctx.page, input, text: ctx.text })) return;\n }\n throw new Error(\"injectPrompt: composer never cleared after 3 send attempts\");\n}\n\n// --- prompt/submit-prompt-attempt.ts ---\n\n/** Context for {@link submitPromptAttempt}. */\ninterface SubmitPromptAttemptContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Composer input locator to fill before sending. */\n input: Locator;\n /** Prompt text to inject into the composer. */\n text: string;\n}\n\n/** Fill the composer and attempt one send; return true when the composer clears. */\nasync function submitPromptAttempt(ctx: SubmitPromptAttemptContext): Promise<boolean> {\n await ctx.input.click();\n await ctx.input.fill(ctx.text);\n await ctx.input.dispatchEvent(\"input\");\n await clickSendButton({ page: ctx.page });\n return composerClears({ page: ctx.page });\n}\n\n// --- response/is-transient-assistant-text.ts ---\n/** Context for {@link isTransientAssistantText}. */\ninterface IsTransientAssistantTextContext {\n /** Normalized assistant response text to inspect. */\n text: string;\n}\n\n/** True when assistant text is a transient placeholder such as \"Thinking…\". */\nfunction isTransientAssistantText(ctx: IsTransientAssistantTextContext): boolean {\n const normalized = ctx.text.trim().toLowerCase();\n return (\n normalized === \"thinking\" ||\n normalized.endsWith(\" thinking\") ||\n normalized.endsWith(\" thinking...\") ||\n /^thinking[.\\s]*$/.test(normalized) ||\n /^thought for\\b/.test(normalized) ||\n normalized.startsWith(\"thought for \")\n );\n}\n\n// --- response/is-turn-settled.ts ---\n\n/**\n * Decide whether the current assistant turn has finished producing output.\n *\n * Pure so the completion policy is unit-testable without a browser.\n */\nfunction isTurnSettled(state: TurnSettledState): boolean {\n if (state.streaming) return false;\n if (state.pendingAssetCount > 0) return false;\n\n const targetImageCount = Math.max(state.expectImages, state.expectedImageMarkerCount);\n const awaitingImages = targetImageCount > 0 || state.sawImageActivity || state.assetCount > 0;\n\n // An image turn must also see the image network fall quiet: every tile that lands resets\n // msSinceImageActivity, so a turn streaming several images never settles between them.\n if (awaitingImages && state.msSinceImageActivity < ASSET_SETTLE_QUIET_MS) return false;\n\n // Fewer tiles have loaded than were requested (via --images) or announced (via [image-N]\n // markers): keep waiting, unless generation has clearly stalled — then settle with what\n // loaded so a short generation never hangs to the full timeout.\n if (targetImageCount > 0 && state.loadedAssetCount < targetImageCount) {\n return state.stableForMs >= IMAGE_STALL_QUIET_MS;\n }\n\n const requiredQuietMs = awaitingImages ? ASSET_SETTLE_QUIET_MS : SETTLE_QUIET_MS;\n if (state.stableForMs < requiredQuietMs) return false;\n\n if (state.loadedAssetCount > 0) return true;\n if (targetImageCount > 0) return false;\n return state.hasText && !state.isTransientText;\n}\n\n// --- response/remaining-timeout.ts ---\n/** Context for {@link remainingTimeout}. */\ninterface RemainingTimeoutContext {\n /** Timestamp when the wait started. */\n startedAt: number;\n /** Total timeout budget in milliseconds. */\n timeout: number;\n}\n\n/** Compute remaining timeout budget, never below one second. */\nfunction remainingTimeout(ctx: RemainingTimeoutContext): number {\n return Math.max(1_000, ctx.timeout - (Date.now() - ctx.startedAt));\n}\n\n// --- response/response-started-after-baseline.ts ---\n\n/** Context for {@link responseStartedAfterBaseline}. */\ninterface ResponseStartedAfterBaselineContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Assistant block count before the prompt was sent. */\n previousAssistantCount?: number;\n /** Last assistant text before the prompt was sent. */\n previousLastAssistantText?: string;\n}\n\n/** True when a new assistant response has started relative to the baseline. */\nasync function responseStartedAfterBaseline(\n ctx: ResponseStartedAfterBaselineContext,\n): Promise<boolean> {\n if (await isStreamingVisible({ page: ctx.page })) return true;\n const count = await ctx.page.locator(SELECTORS.responseBlock).count();\n if (ctx.previousAssistantCount !== undefined && count > ctx.previousAssistantCount) return true;\n const lastText = await readNormalizedLastResponse({ page: ctx.page });\n return (\n !!ctx.previousLastAssistantText && !!lastText && lastText !== ctx.previousLastAssistantText\n );\n}\n\n// --- response/response-wait-options.ts ---\n/** Options for {@link waitForResponse}. */\ninterface ResponseWaitOptions {\n /** Maximum wait time in milliseconds. */\n timeout?: number;\n /** Assistant block count before the prompt was sent. */\n previousAssistantCount?: number;\n /** Last assistant text before the prompt was sent. */\n previousLastAssistantText?: string;\n /** Number of generated images to wait for before the turn counts as settled. */\n expectImages?: number;\n}\n\n// --- response/settle-constants.ts ---\n/** Quiet window a plain text turn must hold before it counts as settled. */\nconst SETTLE_QUIET_MS = 1_500;\n\n/** Longer quiet window required when generated assets are present in a turn. */\nconst ASSET_SETTLE_QUIET_MS = 12_000;\n\n/** Quiet window after which an image turn that fell short of its requested/announced count\n * is treated as finished, so a stopped-short generation never hangs to the full timeout. */\nconst IMAGE_STALL_QUIET_MS = 45_000;\n\n// --- response/streaming-helpers.ts ---\n\n/** Context for {@link isStreamingVisible}. */\ninterface IsStreamingVisibleContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** True when ChatGPT's stop/streaming indicator is visible. */\nasync function isStreamingVisible(ctx: IsStreamingVisibleContext): Promise<boolean> {\n return ctx.page\n .locator(SELECTORS.streamingIndicator)\n .first()\n .isVisible()\n .catch(() => false);\n}\n\n/** Context for {@link readNormalizedLastResponse}. */\ninterface ReadNormalizedLastResponseContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Read and normalize the last assistant response text. */\nasync function readNormalizedLastResponse(ctx: ReadNormalizedLastResponseContext): Promise<string> {\n const text = await captureLastResponse(ctx.page).catch(() => \"\");\n return normalizeDisplayText({ value: text });\n}\n\n// --- response/turn-settled-state.ts ---\n/** Snapshot of assistant turn state used by {@link isTurnSettled}. */\ninterface TurnSettledState {\n /** Whether the assistant block contains non-empty text. */\n hasText: boolean;\n /** Whether the text is a transient placeholder such as \"Thinking…\". */\n isTransientText: boolean;\n /** Count of generated image assets in the current turn. */\n assetCount: number;\n /** Generated images in the current turn that finished loading. */\n loadedAssetCount: number;\n /** Generated images in the current turn still loading or incomplete. */\n pendingAssetCount: number;\n /** Count of `[image-N]` markers in the current turn text. */\n expectedImageMarkerCount: number;\n /** Whether ChatGPT is still streaming the response. */\n streaming: boolean;\n /** Milliseconds the visible content has been unchanged. */\n stableForMs: number;\n /** Generated images the caller asked to wait for (0 when none were requested). */\n expectImages: number;\n /** Whether any generated-image network response has arrived this turn. */\n sawImageActivity: boolean;\n /** Milliseconds since the last generated-image network response (Infinity when none). */\n msSinceImageActivity: number;\n}\n\n// --- response/turn-snapshot.ts ---\n\n/** Context for {@link readTurnSnapshot}. */\ninterface ReadTurnSnapshotContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** Snapshot of the current assistant turn used for settle detection. */\ninterface TurnSnapshot {\n /** Normalized last assistant response text. */\n text: string;\n /** Whether streaming indicator is visible. */\n streaming: boolean;\n /** Count of generated image assets in the last assistant turn. */\n assetCount: number;\n /** Generated images in the last assistant turn that finished loading. */\n loadedAssetCount: number;\n /** Generated images in the last assistant turn still loading or incomplete. */\n pendingAssetCount: number;\n /** Count of `[image-N]` markers in the last assistant turn text. */\n expectedImageMarkerCount: number;\n}\n\n/** Count `[image-N]` markers in assistant text. */\nfunction countExpectedImageMarkers(text: string): number {\n return (text.match(/\\[image-\\d+\\]/g) ?? []).length;\n}\n\n/** True when two turn snapshots differ in a way that resets the settle timer. */\nfunction turnSnapshotChanged(previous: TurnSnapshot, next: TurnSnapshot): boolean {\n return (\n previous.text !== next.text ||\n previous.assetCount !== next.assetCount ||\n previous.loadedAssetCount !== next.loadedAssetCount ||\n previous.pendingAssetCount !== next.pendingAssetCount ||\n previous.expectedImageMarkerCount !== next.expectedImageMarkerCount\n );\n}\n\n/** In-page snapshot of the last assistant turn used for settle detection. */\ninterface LastAssistantTurnState {\n text: string;\n assetCount: number;\n loadedAssetCount: number;\n pendingAssetCount: number;\n expectedImageMarkerCount: number;\n}\n\n/** Read current assistant turn snapshot from the page. */\nasync function readTurnSnapshot(ctx: ReadTurnSnapshotContext): Promise<TurnSnapshot> {\n const turnState = (await ctx.page.evaluate(LAST_ASSISTANT_TURN_STATE_SOURCE).catch(() => ({\n text: \"\",\n assetCount: 0,\n loadedAssetCount: 0,\n pendingAssetCount: 0,\n expectedImageMarkerCount: 0,\n }))) as LastAssistantTurnState;\n const streaming = await isStreamingVisible({ page: ctx.page });\n const text = normalizeDisplayText({\n value: turnState.text || (await readNormalizedLastResponse({ page: ctx.page })),\n });\n const expectedImageMarkerCount = Math.max(\n turnState.expectedImageMarkerCount,\n countExpectedImageMarkers(text),\n );\n return {\n text,\n streaming,\n assetCount: turnState.assetCount,\n loadedAssetCount: turnState.loadedAssetCount,\n pendingAssetCount: turnState.pendingAssetCount,\n expectedImageMarkerCount,\n };\n}\n\n/** Context for {@link turnSnapshotSettled}. */\ninterface TurnSnapshotSettledContext {\n /** Turn snapshot to evaluate. */\n snapshot: TurnSnapshot;\n /** Milliseconds the snapshot has been unchanged. */\n stableForMs: number;\n /** Number of generated images the caller asked to wait for. */\n expectImages: number;\n /** Milliseconds since the last generated-image network response. */\n msSinceImageActivity: number;\n /** Whether any generated-image network response has arrived this turn. */\n sawImageActivity: boolean;\n}\n\n/** True when the snapshot satisfies {@link isTurnSettled}. */\nfunction turnSnapshotSettled(ctx: TurnSnapshotSettledContext): boolean {\n return isTurnSettled({\n hasText: !!ctx.snapshot.text,\n isTransientText: isTransientAssistantText({ text: ctx.snapshot.text }),\n assetCount: ctx.snapshot.assetCount,\n loadedAssetCount: ctx.snapshot.loadedAssetCount,\n pendingAssetCount: ctx.snapshot.pendingAssetCount,\n expectedImageMarkerCount: ctx.snapshot.expectedImageMarkerCount,\n streaming: ctx.snapshot.streaming,\n stableForMs: ctx.stableForMs,\n expectImages: ctx.expectImages,\n msSinceImageActivity: ctx.msSinceImageActivity,\n sawImageActivity: ctx.sawImageActivity,\n });\n}\n\n// --- response/wait-for-last-assistant-text-stable.ts ---\n\n/** Context for {@link waitForLastAssistantTextStable}. */\ninterface WaitForLastAssistantTextStableContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Maximum wait time in milliseconds. */\n timeout: number;\n /** Number of generated images to wait for (0 when the prompt didn't ask for images). */\n expectImages: number;\n /** Live generated-image network activity tracker. */\n imageActivity: ImageNetworkActivity;\n}\n\n/** Wait until assistant text and assets hold still long enough to count as settled. */\nasync function waitForLastAssistantTextStable(\n ctx: WaitForLastAssistantTextStableContext,\n): Promise<void> {\n const startedAt = Date.now();\n let lastSnapshot = await readTurnSnapshot({ page: ctx.page });\n let stableSince = Date.now();\n while (Date.now() - startedAt < ctx.timeout) {\n const snapshot = await readTurnSnapshot({ page: ctx.page });\n if (turnSnapshotChanged(lastSnapshot, snapshot)) {\n lastSnapshot = snapshot;\n stableSince = Date.now();\n }\n if (\n turnSnapshotSettled({\n snapshot,\n stableForMs: Date.now() - stableSince,\n expectImages: ctx.expectImages,\n msSinceImageActivity: ctx.imageActivity.msSinceLastActivity(),\n sawImageActivity: ctx.imageActivity.sawActivity(),\n })\n )\n return;\n await ctx.page.waitForTimeout(500);\n }\n throw new Error(\"Timed out waiting for ChatGPT response to settle.\");\n}\n\n// --- response/wait-for-response-after-baseline.ts ---\n\n/** Context for {@link waitForResponseAfterBaseline}. */\ninterface WaitForResponseAfterBaselineContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Assistant block count before the prompt was sent. */\n previousAssistantCount?: number;\n /** Last assistant text before the prompt was sent. */\n previousLastAssistantText?: string;\n /** Maximum wait time in milliseconds. */\n timeout: number;\n}\n\n/** Wait until ChatGPT begins a new response relative to a pre-send baseline. */\nasync function waitForResponseAfterBaseline(\n ctx: WaitForResponseAfterBaselineContext,\n): Promise<void> {\n const startedAt = Date.now();\n while (Date.now() - startedAt < ctx.timeout) {\n if (await responseStartedAfterBaseline(ctx)) return;\n await ctx.page.waitForTimeout(250);\n }\n throw new Error(\"Timed out waiting for ChatGPT to start a new response.\");\n}\n\n// --- response/image-network-activity.ts ---\n\n/** URL fragments that signal a generated image tile arriving over the network. */\nconst IMAGE_ACTIVITY_URL = /estuary\\/content|oaiusercontent\\.com/i;\n\n/** Tracks generated-image network responses so the settle policy can wait for the image\n * stream to fall quiet, not just for the first tile to render. */\ninterface ImageNetworkActivity {\n /** Milliseconds since the last image response, or Infinity when none has arrived. */\n msSinceLastActivity(): number;\n /** Whether any generated-image response has arrived this turn. */\n sawActivity(): boolean;\n /** Detach the underlying page listener. */\n dispose(): void;\n}\n\n/** Attach a response listener that timestamps generated-image network activity on the page. */\nfunction trackImageNetworkActivity(page: Page): ImageNetworkActivity {\n let lastActivityAt = 0;\n const onResponse = (response: Response): void => {\n if (IMAGE_ACTIVITY_URL.test(response.url())) lastActivityAt = Date.now();\n };\n page.on(\"response\", onResponse);\n return {\n msSinceLastActivity: () =>\n lastActivityAt === 0 ? Number.POSITIVE_INFINITY : Date.now() - lastActivityAt,\n sawActivity: () => lastActivityAt !== 0,\n dispose: () => page.off(\"response\", onResponse),\n };\n}\n\n// --- response/wait-for-response.ts ---\n\n/** Wait for ChatGPT to finish streaming its response, including any generated images. */\nasync function waitForResponse(\n page: Page,\n options: number | ResponseWaitOptions = {},\n): Promise<void> {\n const parsed = parseResponseWaitOptions(options);\n const startedAt = Date.now();\n const imageActivity = trackImageNetworkActivity(page);\n try {\n if (parsed.previousAssistantCount !== undefined || parsed.previousLastAssistantText) {\n await waitForResponseAfterBaseline({ page, ...parsed });\n } else {\n await page.waitForSelector(SELECTORS.responseBlock, { timeout: parsed.timeout });\n }\n await waitForStreamingToFinish({ page, startedAt, timeout: parsed.timeout });\n await waitForLastAssistantTextStable({\n page,\n timeout: remainingTimeout({ startedAt, timeout: parsed.timeout }),\n expectImages: parsed.expectImages ?? 0,\n imageActivity,\n });\n } finally {\n imageActivity.dispose();\n }\n}\n\n// --- response/wait-for-streaming-to-finish.ts ---\n\n/** Context for {@link waitForStreamingToFinish}. */\ninterface WaitForStreamingToFinishContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n /** Timestamp when the wait started. */\n startedAt: number;\n /** Total timeout budget in milliseconds. */\n timeout: number;\n}\n\n/** Wait for the streaming indicator to appear then disappear. */\nasync function waitForStreamingToFinish(ctx: WaitForStreamingToFinishContext): Promise<void> {\n try {\n await ctx.page\n .locator(SELECTORS.streamingIndicator)\n .waitFor({ state: \"visible\", timeout: 10_000 });\n await ctx.page.locator(SELECTORS.streamingIndicator).waitFor({\n state: \"hidden\",\n timeout: remainingTimeout({ startedAt: ctx.startedAt, timeout: ctx.timeout }),\n });\n } catch {\n // Response might already be complete\n }\n}\n\n/** Parse {@link waitForResponse} options from a number or options object. */\nfunction parseResponseWaitOptions(options: number | ResponseWaitOptions): {\n timeout: number;\n previousAssistantCount?: number;\n previousLastAssistantText?: string;\n expectImages?: number;\n} {\n if (typeof options === \"number\") {\n return { timeout: options };\n }\n return {\n timeout: options.timeout ?? 300_000,\n previousAssistantCount: options.previousAssistantCount,\n previousLastAssistantText: normalizeDisplayText({\n value: options.previousLastAssistantText ?? \"\",\n }),\n expectImages: options.expectImages,\n };\n}\n\n// --- selectors.config.ts ---\n/** DOM selectors for ChatGPT's interface. Subject to change if ChatGPT updates UI. */\nconst SELECTORS = {\n /** The contenteditable prompt input field. */\n promptInput: PROVIDER_CONFIG.chatgpt.selectors.composer,\n /** The send button (visible when text is entered). */\n sendButton:\n 'button[data-testid=\"send-button\"], button[aria-label=\"Send prompt\"], button[aria-label=\"Send message\"]',\n /** Individual assistant response blocks. */\n responseBlock: PROVIDER_CONFIG.chatgpt.selectors.assistant,\n /** The most recent response block. */\n lastResponse: `${PROVIDER_CONFIG.chatgpt.selectors.assistant}:last-of-type`,\n /** Sidebar conversation links. */\n sidebarConversation: 'nav a[href^=\"/c/\"]',\n /** Streaming indicator (the stop button appears while streaming). */\n streamingIndicator: [\n 'button[aria-label=\"Stop generating\"]',\n 'button[aria-label=\"Stop streaming\"]',\n 'button[aria-label*=\"Stop\" i]',\n 'button[data-testid=\"stop-button\"]',\n ].join(\", \"),\n /** ChatGPT-generated images render outside the role block, served from the estuary content endpoint. */\n generatedImage: 'img[src*=\"/backend-api/estuary/content\"], img[alt^=\"Generated image\" i]',\n /** Model menu triggers in the ChatGPT shell. */\n modelTrigger: [\n 'button[data-testid=\"model-switcher-dropdown-button\"]',\n 'button[aria-label=\"Switch model\"]',\n 'button:has-text(\"GPT\")',\n 'button:has-text(\"ChatGPT\")',\n 'button:has-text(\"o3\")',\n 'button:has-text(\"o4\")',\n ],\n /** Open dropdown / menu content. */\n openMenu: '[role=\"menu\"], [data-radix-menu-content], [data-radix-popper-content-wrapper]',\n /** User message blocks. */\n userBlock: '[data-message-author-role=\"user\"]',\n /** Conversation turn wrapper. */\n conversationTurn: 'section[data-testid^=\"conversation-turn-\"]',\n /** Composer file attachment controls. */\n attachmentInput: 'input[type=\"file\"]',\n attachmentButton: [\n 'button[aria-label*=\"Attach\" i]',\n 'button[aria-label*=\"Upload\" i]',\n 'button[data-testid*=\"attach\" i]',\n 'button[data-testid*=\"upload\" i]',\n ],\n /** Profile/settings controls. */\n accountMenuButton: [\n '[data-testid=\"accounts-profile-button\"]',\n '[role=\"button\"][aria-label*=\"open profile menu\" i]',\n 'button[data-testid=\"profile-button\"]',\n 'button[aria-label*=\"profile\" i]',\n 'button[aria-label*=\"account\" i]',\n 'button[aria-label*=\"user\" i]',\n ],\n settingsEntrypoint: [\n '[role=\"menuitem\"]:has-text(\"Settings\")',\n 'button:has-text(\"Settings\")',\n 'a:has-text(\"Settings\")',\n ],\n} as const;\n\n// --- session/assert-signed-in.ts ---\n\n/** Fail fast before sending a prompt to an unauthenticated guest session. */\nasync function assertSignedIn(page: Page): Promise<void> {\n if (await isGuestSession(page)) {\n throw new GuestSessionError(\n \"ChatGPT is not signed in. \" +\n \"This is the bridge's isolated Chrome — not your daily browser. \" +\n \"Click Log in in that window, complete sign-in, leave it open, then run again.\",\n );\n }\n}\n\n// --- session/has-guest-login-buttons.ts ---\n\n/** Context for {@link hasGuestLoginButtons}. */\ninterface HasGuestLoginButtonsContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** True when ChatGPT shows login or signup CTAs for guest users. */\nasync function hasGuestLoginButtons(ctx: HasGuestLoginButtonsContext): Promise<boolean> {\n const login = ctx.page.locator('[data-testid=\"login-button\"]');\n if (await login.isVisible({ timeout: 1500 }).catch(() => false)) return true;\n const signup = ctx.page.locator('[data-testid=\"signup-button\"]');\n return signup.isVisible({ timeout: 500 }).catch(() => false);\n}\n\n// --- session/has-visible-account-menu.ts ---\n\n/** Context for {@link hasVisibleAccountMenu}. */\ninterface HasVisibleAccountMenuContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** True when the signed-in account/profile menu control is visible. */\nasync function hasVisibleAccountMenu(ctx: HasVisibleAccountMenuContext): Promise<boolean> {\n const account = ctx.page.locator(SELECTORS.accountMenuButton.join(\", \"));\n return account\n .first()\n .isVisible({ timeout: 2500 })\n .catch(() => false);\n}\n\n// --- session/has-visible-composer.ts ---\n\n/** Context for {@link hasVisibleComposer}. */\ninterface HasVisibleComposerContext {\n /** Playwright page handle for the ChatGPT tab. */\n page: Page;\n}\n\n/** True when the prompt composer input is visible on the page. */\nasync function hasVisibleComposer(ctx: HasVisibleComposerContext): Promise<boolean> {\n const prompt = ctx.page.locator(SELECTORS.promptInput);\n return prompt\n .first()\n .isVisible({ timeout: 1500 })\n .catch(() => false);\n}\n\n// --- session/is-guest-session.ts ---\n\n/** True when ChatGPT is showing the unauthenticated guest shell. */\nasync function isGuestSession(page: Page): Promise<boolean> {\n if (await hasVisibleAccountMenu({ page })) return false;\n if (await hasGuestLoginButtons({ page })) return true;\n return !(await hasVisibleComposer({ page }));\n}\n\n/** ChatGPT web UI automation — prompt, response, model, connector, attachments. */\nexport class ChatGptPage implements BrowserProvider {\n readonly id = \"chatgpt\" as const;\n readonly origin = \"chatgpt.com\";\n readonly defaultUrl = \"https://chatgpt.com\";\n readonly defaultModel = \"ChatGPT\";\n readonly displayName = \"ChatGPT\";\n readonly composerSelector = PROVIDER_CONFIG.chatgpt.selectors.composer;\n readonly supportsMcpConnector = true;\n\n /** Fail fast when ChatGPT is not signed in. */\n async assertSignedIn(page: Page): Promise<void> {\n return assertSignedIn(page);\n }\n\n /** Type a prompt into the composer and send it. */\n async injectPrompt(page: Page, text: string): Promise<void> {\n return injectPrompt(page, text);\n }\n\n /** Wait until the assistant response finishes streaming. */\n async waitForResponse(page: Page, options?: number | ResponseWaitOptions): Promise<void> {\n return waitForResponse(page, options);\n }\n\n /** Read the last assistant response text from the page. */\n async captureLastResponse(page: Page): Promise<string> {\n return captureLastResponse(page);\n }\n\n /** Count rendered assistant response blocks. */\n async countAssistantResponses(page: Page): Promise<number> {\n return countAssistantResponses(page);\n }\n\n /** Capture all conversation messages from the DOM. */\n async captureAllMessages(page: Page): Promise<Array<{ role: string; content: string }>> {\n return captureAllMessages(page);\n }\n\n /** Read conversation entries from the sidebar. */\n async readSidebarConversations(\n page: Page,\n ): Promise<Array<{ id: string; title: string; url: string }>> {\n return readSidebarConversations(page);\n }\n\n /** Navigate to a conversation URL. */\n async navigateToConversation(page: Page, url: string): Promise<void> {\n return navigateToConversation(page, url);\n }\n\n /** Open a new ChatGPT conversation. */\n async newConversation(page: Page): Promise<void> {\n return newConversation(page);\n }\n\n /** Detect the currently selected model label. */\n async detectCurrentModel(page: Page): Promise<string> {\n return detectCurrentModel(page);\n }\n\n /** List models exposed in the model picker. */\n async listAvailableModels(page: Page): Promise<ModelOption[]> {\n return listAvailableModels(page);\n }\n\n /** Switch to a model matching the query string. */\n async selectModel(page: Page, query: string): Promise<string> {\n return selectModel(page, query);\n }\n\n /** Rewind and optionally replace the last user prompt. */\n async rewindLastUserPrompt(page: Page, replacement?: string): Promise<void> {\n return rewindLastUserPrompt(page, replacement);\n }\n\n /** Stop an in-progress response stream when possible. */\n async stopGenerating(page: Page, timeout?: number): Promise<boolean> {\n return stopGenerating(page, timeout);\n }\n\n /** Attach local files to the composer. */\n async attachFilesToPrompt(page: Page, paths: string[]): Promise<void> {\n return attachFilesToPrompt(page, paths);\n }\n\n /** True when a string looks like a ChatGPT model label. */\n isLikelyModelLabel(value: string): boolean {\n return isLikelyModelLabel(value);\n }\n\n /** Set up the ChatGPT MCP connector in Developer Mode. */\n async setupMcpConnector(\n page: Page,\n url: string,\n options?: ConnectorSetupOptions,\n ): Promise<ConnectorSetupResult> {\n return setupMcpConnectorInChatGpt(page, url, options);\n }\n}\n\nexport {\n AttachmentDownloadError,\n countExpectedImageMarkers,\n downloadAll,\n downloadAttachment,\n extractAllMessages,\n extractAssistantContent,\n injectPrompt,\n isTurnSettled,\n loadManifest,\n readComposerText,\n saveManifest,\n SELECTORS,\n};\n","/** DOM selectors describing a web-chat provider's core surface. */\nexport interface ProviderSelectors {\n /** Composer input (contenteditable or textarea). */\n composer: string;\n /** Container for a single assistant message; the last match is the latest reply. */\n assistant: string;\n /** Container for a single user message (optional; enables full transcript capture). */\n user?: string;\n /** Stop-generating control (optional). */\n stop?: string;\n /** Send-message button; clicked when set and visible, otherwise Enter is pressed (optional). */\n send?: string;\n /** Button that starts a new conversation (optional; falls back to navigating home). */\n newChat?: string;\n /** A conversation link in the history sidebar (optional; enables history listing). */\n sidebarItem?: string;\n /** Button opening the model picker; its visible text is the current model (optional). */\n modelTrigger?: string;\n /** Model option items inside the open picker (optional; enables model switching). */\n modelOption?: string;\n /** File input for attaching local files to the prompt (optional). */\n attach?: string;\n /** Element whose presence means \"not signed in\" (optional). */\n signedOut?: string;\n}\n\n/** Static metadata + core selectors for a supported browser provider. */\nexport interface ProviderConfigEntry {\n /** Human-readable name for CLI/TUI and logs. */\n displayName: string;\n /** Whether MCP connector setup is supported (ChatGPT and Claude today). */\n supportsMcpConnector: boolean;\n /** Origin hostname used to locate an existing tab. */\n origin: string;\n /** URL opened when no provider tab exists. */\n defaultUrl: string;\n /** Fallback model label before detection runs. */\n defaultModel: string;\n /** Core DOM selectors (composer + assistant, plus optional extras). */\n selectors: ProviderSelectors;\n}\n\n/**\n * Single source of truth for supported web-chat providers, keyed by id.\n * The provider id type, the CLI `--provider` help, `bridge login`, and the browser\n * adapters all derive from this table. Adding a provider is one entry here plus (for a\n * bespoke DOM) a `*Page` class — the registry binds behavior, never redeclares metadata.\n *\n * Optional functional selectors (newChat / sidebarItem / modelTrigger / attach) are the\n * live-verified affordances the generic adapter un-stubs per provider; capture them with\n * `src/scripts/dev/captureProviderSelectors.mjs` against the real signed-in DOM.\n */\nexport const PROVIDER_CONFIG = {\n chatgpt: {\n displayName: \"ChatGPT\",\n supportsMcpConnector: true,\n origin: \"chatgpt.com\",\n defaultUrl: \"https://chatgpt.com\",\n defaultModel: \"ChatGPT\",\n selectors: {\n composer: '#prompt-textarea, [contenteditable=\"true\"]',\n assistant: '[data-message-author-role=\"assistant\"]',\n },\n },\n gemini: {\n displayName: \"Gemini\",\n supportsMcpConnector: false,\n origin: \"gemini.google.com\",\n defaultUrl: \"https://gemini.google.com/app\",\n defaultModel: \"Gemini\",\n selectors: {\n composer: 'div.ql-editor, [contenteditable=\"true\"]',\n assistant: \"model-response, message-content, .model-response-text, .response-content\",\n },\n },\n claude: {\n displayName: \"Claude\",\n supportsMcpConnector: true,\n origin: \"claude.ai\",\n defaultUrl: \"https://claude.ai/new\",\n defaultModel: \"Claude\",\n selectors: {\n composer: '[data-testid=\"chat-input\"], div[contenteditable=\"true\"]',\n assistant: \".standard-markdown\",\n user: '[data-testid=\"user-message\"]',\n stop: 'button[aria-label=\"Stop response\"]',\n send: 'button[aria-label=\"Send message\"]',\n newChat: 'a[aria-label=\"New chat\"]',\n sidebarItem: 'nav a[href*=\"/chat/\"]',\n modelTrigger: '[data-testid=\"model-selector-dropdown\"]',\n modelOption: '[role=\"menuitem\"], [role=\"menuitemradio\"]',\n attach: 'input[data-testid=\"file-upload\"]',\n signedOut: 'a[href*=\"/login\"]',\n },\n },\n deepseek: {\n displayName: \"DeepSeek\",\n supportsMcpConnector: false,\n origin: \"chat.deepseek.com\",\n defaultUrl: \"https://chat.deepseek.com/\",\n defaultModel: \"DeepSeek\",\n selectors: {\n composer: \"textarea#chat-input, textarea\",\n assistant: \".ds-markdown\",\n stop: 'div[role=\"button\"][aria-label*=\"Stop\"]',\n sidebarItem: 'a[href*=\"/a/chat/s/\"]',\n attach: 'input[type=\"file\"]',\n signedOut: 'button:has-text(\"Log in\")',\n },\n },\n grok: {\n displayName: \"Grok\",\n supportsMcpConnector: false,\n origin: \"grok.com\",\n defaultUrl: \"https://grok.com/\",\n defaultModel: \"Grok\",\n selectors: {\n composer: '[aria-label=\"Ask Grok anything\"], div.tiptap.ProseMirror, textarea',\n assistant: '[class*=\"message-bubble\"]',\n stop: 'button[aria-label*=\"Stop\"]',\n newChat: '[data-testid=\"new-chat\"]',\n sidebarItem: 'a[href*=\"/c/\"]',\n modelTrigger: 'button[aria-label=\"Model select\"]',\n modelOption: '[role=\"menuitem\"], [role=\"menuitemradio\"]',\n attach: 'input[type=\"file\"]',\n signedOut: 'button:has-text(\"Sign in\")',\n },\n },\n perplexity: {\n displayName: \"Perplexity\",\n supportsMcpConnector: false,\n origin: \"perplexity.ai\",\n defaultUrl: \"https://www.perplexity.ai/\",\n defaultModel: \"Perplexity\",\n selectors: {\n composer: '#ask-input, textarea, div[contenteditable=\"true\"]',\n assistant: \".prose\",\n stop: 'button[aria-label*=\"Stop\"]',\n send: 'button[aria-label=\"Submit\"]',\n sidebarItem: 'a[href*=\"/search/\"]',\n modelTrigger: 'button[aria-label=\"Model\"]',\n modelOption: '[role=\"menuitem\"], [role=\"menuitemradio\"]',\n attach: 'input[type=\"file\"]',\n signedOut: 'button:has-text(\"Sign Up\")',\n },\n },\n} satisfies Record<string, ProviderConfigEntry>;\n\n/** Supported provider id — derived from the config keys (the single source of truth). */\nexport type BridgeProviderId = keyof typeof PROVIDER_CONFIG;\n\n/** All supported provider ids, in config order. */\nexport const PROVIDER_IDS = Object.keys(PROVIDER_CONFIG) as BridgeProviderId[];\n\n/** Provider used when a command specifies none. */\nexport const DEFAULT_PROVIDER: BridgeProviderId = \"chatgpt\";\n\n/** Human-typed aliases mapped to canonical ids. */\nexport const PROVIDER_ALIASES: Record<string, BridgeProviderId> = {\n gpt: \"chatgpt\",\n \"chat-gpt\": \"chatgpt\",\n bard: \"gemini\",\n \"claude.ai\": \"claude\",\n anthropic: \"claude\",\n x: \"grok\",\n ppl: \"perplexity\",\n};\n","/** Default MCP server listen port. */\nexport const DEFAULT_MCP_PORT = 8765;\n\n/** Default context window when model is unknown. */\nexport const DEFAULT_CONTEXT_LIMIT = 128_000;\n\n/** Default permission mode for tool execution. */\nexport const DEFAULT_PERMISSION_MODE = \"auto\" as const;\n\n/** Default ask timeout in seconds (headless). */\nexport const DEFAULT_ASK_TIMEOUT_SECONDS = 300;\n","import { Config } from \"effect\";\n\n/**\n * Repo root path, resolved from `BRIDGE_REPO_PATH` env var.\n * @returns The configured repo path or the current working directory.\n */\nexport const RepoPathConfig = Config.string(\"BRIDGE_REPO_PATH\").pipe(\n Config.withDefault(process.cwd()),\n);\n\n/**\n * MCP server listen port, resolved from `BRIDGE_MCP_PORT` env var.\n * @returns The configured port or `8765`.\n */\nexport const McpPortConfig = Config.integer(\"BRIDGE_MCP_PORT\").pipe(Config.withDefault(8765));\n\n/**\n * Active provider id, resolved from `BRIDGE_PROVIDER` env var.\n * @returns The configured provider or `\"chatgpt\"`.\n */\nexport const ProviderConfig = Config.string(\"BRIDGE_PROVIDER\").pipe(Config.withDefault(\"chatgpt\"));\n","/** Extract a ChatGPT `/c/<id>` conversation id from a URL, or null when absent. */\nexport function conversationIdFromUrl(url: string): string | null {\n const match = /\\/c\\/([^/?#]+)/.exec(url);\n return match?.[1] ?? null;\n}\n\n/** Normalize a conversation flag (id or full URL) to a canonical ChatGPT thread URL. */\nexport function conversationUrlFromIdOrUrl(value: string): string {\n const trimmed = value.trim();\n if (trimmed.startsWith(\"http://\") || trimmed.startsWith(\"https://\")) return trimmed;\n return `https://chatgpt.com/c/${trimmed}`;\n}\n\n/** True when `pageUrl` is already on the same ChatGPT conversation as `target`. */\nexport function isSameChatGptConversation(pageUrl: string, targetIdOrUrl: string): boolean {\n const targetId = conversationIdFromUrl(conversationUrlFromIdOrUrl(targetIdOrUrl));\n const currentId = conversationIdFromUrl(pageUrl);\n return !!targetId && targetId === currentId;\n}\n","/** Thrown when a provider shows its unauthenticated sign-in shell. */\nexport class GuestSessionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"GuestSessionError\";\n }\n}\n","import type { Locator, Page } from \"playwright\";\n\n// ChatGPT workspace operations — Projects, chat→project moves, and Scheduled tasks — driven\n// through the signed-in web UI. These are ChatGPT-only and deliberately NOT part of the shared\n// BrowserProvider interface (Gemini has no equivalent), so they live beside chatgptPage.ts as\n// standalone functions that take a Playwright Page. Selectors were captured against the live\n// DOM (see src/scripts/dev/captureChatgptSelectors.mjs); the stable data-testids are preferred and\n// text/role locators back them up where ChatGPT ships no testid.\n\n/** A ChatGPT Project (a named folder that groups conversations). */\nexport interface WorkspaceProject {\n /** Human-visible project name. */\n name: string;\n}\n\n/** Outcome of moving one conversation into a project. */\nexport interface MoveChatOutcome {\n /** Chat title or id the caller asked to move. */\n chat: string;\n /** Target project name. */\n project: string;\n /** Whether the move actually happened. */\n moved: boolean;\n /** Why the move was skipped, when `moved` is false. */\n reason?: string;\n}\n\n/** A ChatGPT Scheduled task (an automation that runs on a cadence). */\nexport interface WorkspaceTask {\n /** Task title as rendered on the Scheduled page. */\n title: string;\n /** Cadence/next-run text when ChatGPT exposes it. */\n schedule?: string;\n}\n\n/** Workspace DOM selectors, captured from the live ChatGPT UI. */\nconst WORKSPACE = {\n projectsUrl: \"https://chatgpt.com/projects\",\n scheduledUrl: \"https://chatgpt.com/scheduled\",\n sidebarProjects: '[data-testid=\"sidebar-item-projects\"]',\n sidebarTasks: '[data-testid=\"sidebar-item-tasks\"]',\n newProjectButton: 'button[aria-label=\"New project\"]',\n projectNameInput: 'input[name=\"projectName\"]',\n projectFolderIcon: '[data-testid=\"project-folder-icon\"]',\n chatLink: 'nav a[href^=\"/c/\"]',\n menuItem: '[role=\"menuitem\"]',\n} as const;\n\n// --- projects/list-projects.ts ---\n\n/** In-page scrape of project rows on the /projects table. The project name is the first\n * text-bearing leaf in the row (the primary-text cell); date columns follow it. */\nconst PROJECT_ROWS_SOURCE = String.raw`\n(() => {\n const clean = (s) => (s || \"\").replace(/\\s+/g, \" \").trim();\n const rows = Array.from(document.querySelectorAll('[data-testid=\"project-folder-icon\"]'))\n .map((icon) => icon.closest('[role=\"row\"], a[href], li'))\n .filter(Boolean);\n const names = [];\n const seen = new Set();\n for (const row of rows) {\n const leaf = Array.from(row.querySelectorAll(\"*\")).find(\n (el) => el.children.length === 0 && clean(el.textContent),\n );\n const name = clean(leaf ? leaf.textContent : row.textContent);\n if (!name || seen.has(name)) continue;\n seen.add(name);\n names.push(name);\n }\n return names;\n})()\n`;\n\n/** List the ChatGPT Projects visible on the /projects page. */\nexport async function listProjects(page: Page): Promise<WorkspaceProject[]> {\n await ensureOnProjectsPage(page);\n await page\n .locator(WORKSPACE.projectFolderIcon)\n .first()\n .waitFor({ timeout: 5_000 })\n .catch(() => {});\n const names = await page.evaluate<string[]>(PROJECT_ROWS_SOURCE);\n return names.map((name) => ({ name }));\n}\n\n/** Navigate to the /projects page when the active tab is elsewhere. */\nasync function ensureOnProjectsPage(page: Page): Promise<void> {\n if (page.url().startsWith(WORKSPACE.projectsUrl)) return;\n await page.goto(WORKSPACE.projectsUrl, { waitUntil: \"domcontentloaded\" });\n await page.waitForTimeout(800);\n}\n\n// --- projects/create-project.ts ---\n\n/** Create a new ChatGPT Project and return its record. Throws if the name field never appears. */\nexport async function createProject(page: Page, name: string): Promise<WorkspaceProject> {\n const trimmed = name.trim();\n if (!trimmed) throw new Error(\"Project name is required.\");\n await openNewProjectPanel(page);\n const field = page.locator(WORKSPACE.projectNameInput).first();\n await field.waitFor({ state: \"visible\", timeout: 8_000 });\n await field.fill(trimmed);\n await submitCreateProject(page);\n await page.waitForTimeout(1_200);\n return { name: trimmed };\n}\n\n/** Reveal and click the sidebar \"New project\" control (hover-revealed at rest). */\nasync function openNewProjectPanel(page: Page): Promise<void> {\n await page\n .locator(WORKSPACE.sidebarProjects)\n .first()\n .hover()\n .catch(() => {});\n await page.waitForTimeout(200);\n await page.locator(WORKSPACE.newProjectButton).first().click({ force: true, timeout: 8_000 });\n}\n\n/** Submit the \"Create project\" panel via its button, falling back to Enter. */\nasync function submitCreateProject(page: Page): Promise<void> {\n const button = page.getByRole(\"button\", { name: /create project/i }).first();\n if (await button.isVisible({ timeout: 2_000 }).catch(() => false)) {\n await button.click();\n return;\n }\n await page.locator(WORKSPACE.projectNameInput).first().press(\"Enter\");\n}\n\n// --- chats/move-chat-to-project.ts ---\n\n/** Input for {@link moveChatToProject}. */\nexport interface MoveChatInput {\n /** Conversation id (`/c/<id>`) or exact chat title as shown in the sidebar. */\n chat: string;\n /** Destination project name (must already exist). */\n project: string;\n}\n\n/** Move a sidebar conversation into a project via its ⋯ menu. Reports (never throws) on skips. */\nexport async function moveChatToProject(\n page: Page,\n input: MoveChatInput,\n): Promise<MoveChatOutcome> {\n const base: MoveChatOutcome = { chat: input.chat, project: input.project, moved: false };\n const row = await findChatRow(page, input.chat);\n if (!row) return { ...base, reason: \"chat not found in the sidebar\" };\n if (!(await openChatMenu(page, row))) {\n return { ...base, reason: \"could not open the chat ⋯ menu\" };\n }\n const moveItem = page.getByRole(\"menuitem\", { name: /move to project/i }).first();\n if (!(await moveItem.isVisible({ timeout: 2_000 }).catch(() => false))) {\n await dismissMenu(page);\n return { ...base, reason: \"no 'Move to project' option (GPT- or project-owned chat)\" };\n }\n await moveItem.hover();\n await page.waitForTimeout(500);\n const target = page.getByRole(\"menuitem\", { name: exactName(input.project) }).first();\n if (!(await target.isVisible({ timeout: 2_000 }).catch(() => false))) {\n await dismissMenu(page);\n return { ...base, reason: `project \"${input.project}\" not found — create it first` };\n }\n await target.click();\n await page.waitForTimeout(800);\n return { ...base, moved: true };\n}\n\n/** Locate a sidebar chat row by conversation id or exact title. */\nasync function findChatRow(page: Page, chat: string) {\n const byHref = page.locator(`nav a[href=\"/c/${stripConversationId(chat)}\"]`).first();\n if ((await byHref.count()) > 0) return byHref;\n const byTitle = page.locator(WORKSPACE.chatLink, { hasText: chat }).first();\n return (await byTitle.count()) > 0 ? byTitle : null;\n}\n\n/** Hover a chat row and force-click its (hover-revealed) ⋯ options button. */\nasync function openChatMenu(page: Page, row: Locator): Promise<boolean> {\n await row.hover().catch(() => {});\n await page.waitForTimeout(200);\n const options = row\n .locator('xpath=following-sibling::*//button[contains(@aria-label,\"conversation options\")]')\n .first();\n const trigger = (await options.count()) > 0 ? options : row.getByRole(\"button\").last();\n try {\n await trigger.click({ force: true, timeout: 5_000 });\n await page.locator(WORKSPACE.menuItem).first().waitFor({ timeout: 4_000 });\n return true;\n } catch {\n return false;\n }\n}\n\n/** Close any open popover menu without selecting an item. */\nasync function dismissMenu(page: Page): Promise<void> {\n await page.keyboard.press(\"Escape\").catch(() => {});\n await page.keyboard.press(\"Escape\").catch(() => {});\n}\n\n// --- tasks/list-tasks.ts ---\n\n/** In-page scrape of scheduled-task rows on the /scheduled page. */\nconst SCHEDULED_ROWS_SOURCE = String.raw`\n(() => {\n const clean = (s) => (s || \"\").replace(/\\s+/g, \" \").trim();\n const main = document.querySelector('main, [role=\"main\"]') || document.body;\n const rows = Array.from(main.querySelectorAll('[role=\"row\"], li, article'));\n const tasks = [];\n const seen = new Set();\n for (const row of rows) {\n const title = clean((row.querySelector('[role=\"gridcell\"], h2, h3, a') || row).textContent);\n if (!title || seen.has(title)) continue;\n seen.add(title);\n tasks.push({ title });\n }\n return tasks;\n})()\n`;\n\n/** List ChatGPT Scheduled tasks. Returns an empty array when none are configured. */\nexport async function listTasks(page: Page): Promise<WorkspaceTask[]> {\n if (!page.url().startsWith(WORKSPACE.scheduledUrl)) {\n await page.goto(WORKSPACE.scheduledUrl, { waitUntil: \"domcontentloaded\" });\n await page.waitForTimeout(1_200);\n }\n return page.evaluate<WorkspaceTask[]>(SCHEDULED_ROWS_SOURCE);\n}\n\n// --- shared ---\n\n/** Escape a project/chat name into an exact-match RegExp for getByRole name lookups. */\nexport function exactName(value: string): RegExp {\n return new RegExp(`^${value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}$`);\n}\n\n/** Reduce a `/c/<id>` URL or bare id to just the conversation id. */\nexport function stripConversationId(idOrUrl: string): string {\n const match = idOrUrl.match(/\\/c\\/([^/?#]+)/);\n return match?.[1] ?? idOrUrl;\n}\n","import { execFile, spawn } from \"node:child_process\";\nimport { mkdirSync, realpathSync, writeFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport type { Conversation } from \"@/features/domain\";\nimport { bridgeDir, chromeProfileDir } from \"@/features/store\";\nimport type { Browser, BrowserContext, Page, Response } from \"playwright\";\nimport { chromium } from \"playwright\";\nimport type { BrowserProvider } from \"../../browserProviderTypes.ts\";\nimport { type BridgeProviderId, getBrowserProvider } from \"../../providerRegistry.ts\";\n\n/** Chrome remote-debugging port the bridge attaches to / spawns on. */\nexport const BRIDGE_DEBUG_PORT = 9222;\n\nconst CHROME_BIN = \"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\";\nconst CDP_URL = `http://127.0.0.1:${BRIDGE_DEBUG_PORT}`;\nconst execFileAsync = promisify(execFile);\n\n/** Parse `--user-data-dir=` from the Chrome process bound to a debug port. */\nexport async function getUserDataDirOnDebugPort(\n port: number = BRIDGE_DEBUG_PORT,\n): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"ps\", [\"ax\", \"-o\", \"command=\"]);\n const needle = `--remote-debugging-port=${port}`;\n for (const line of stdout.split(\"\\n\")) {\n if (\n !line.includes(needle) ||\n !line.includes(\"Google Chrome.app/Contents/MacOS/Google Chrome\")\n )\n continue;\n const match = line.match(/--user-data-dir=([^\\s]+)/);\n if (match?.[1]) return match[1];\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/** Whether two profile directories refer to the same path. */\nexport function profilesMatch(expected: string, actual: string): boolean {\n const normalize = (value: string): string => {\n try {\n return realpathSync(resolve(value));\n } catch {\n return resolve(value);\n }\n };\n return normalize(expected) === normalize(actual);\n}\n\nasync function waitForDebugPortClosed(port: number, maxWaitMs = 10_000): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < maxWaitMs) {\n if (!(await isDebugPortListening({ port }))) return;\n await sleep(250);\n }\n}\n\n/** Stop Chrome processes listening on the debug port (wrong profile recovery). */\nexport async function terminateChromeOnDebugPort(port: number = BRIDGE_DEBUG_PORT): Promise<void> {\n try {\n await execFileAsync(\"pkill\", [\"-f\", `--remote-debugging-port=${port}`]);\n } catch {\n /* no matching process */\n }\n await waitForDebugPortClosed(port);\n}\n\n/** Raised when Chrome is open but not reachable on the debug port. */\nexport class BrowserAttachError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BrowserAttachError\";\n }\n}\n\n/** Whether localhost responds on the Chrome remote debugging port. */\nexport async function isDebugPortListening(\n input: { port?: number } | number = {},\n): Promise<boolean> {\n const port = typeof input === \"number\" ? input : (input.port ?? BRIDGE_DEBUG_PORT);\n try {\n const resp = await fetch(`http://127.0.0.1:${port}/json/version`);\n return resp.ok;\n } catch {\n return false;\n }\n}\n\n/** Whether a Google Chrome process is running on macOS. */\nexport function isChromeProcessRunning(_input: { unused?: true } = {}): Promise<boolean> {\n return new Promise((done) => {\n execFile(\"pgrep\", [\"-x\", \"Google Chrome\"], (...execArgs) => {\n const err = execArgs[0] as NodeJS.ErrnoException | null;\n const stdout = execArgs[1] as string;\n done(!err && stdout.trim().length > 0);\n });\n });\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function waitForDebugPort(port: number, maxWaitMs = 30_000): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < maxWaitMs) {\n if (await isDebugPortListening({ port })) return;\n await sleep(500);\n }\n throw new Error(`Timed out waiting for Chrome debug port ${port}`);\n}\n\nfunction prepareProfileDirectories(repoPath: string, profileDir: string): void {\n mkdirSync(bridgeDir(repoPath), { recursive: true });\n writeFileSync(join(bridgeDir(repoPath), \".gitignore\"), \"*\\n\");\n mkdirSync(profileDir, { recursive: true });\n}\n\nfunction spawnChrome(profileDir: string, defaultUrl: string): void {\n const child = spawn(\n CHROME_BIN,\n [\n `--user-data-dir=${profileDir}`,\n `--remote-debugging-port=${BRIDGE_DEBUG_PORT}`,\n \"--no-first-run\",\n \"--no-default-browser-check\",\n defaultUrl,\n ],\n { detached: true, stdio: \"ignore\" },\n );\n child.unref();\n}\n\nfunction attachOnlyError(): BrowserAttachError {\n return new BrowserAttachError(\n `No Chrome listening on debug port ${BRIDGE_DEBUG_PORT}. Launch Chrome with --remote-debugging-port=9222 or run \\`bridge login\\`.`,\n );\n}\n\nfunction chromeAlreadyRunningError(): BrowserAttachError {\n return new BrowserAttachError(\n \"Chrome is already running without the bridge debug port. The bridge will not open a second window.\",\n );\n}\n\nfunction spawnReadyError(): BrowserAttachError {\n return new BrowserAttachError(\n `Chrome started but debug port ${BRIDGE_DEBUG_PORT} did not become ready.`,\n );\n}\n\ninterface CdpConnectState {\n browser: Browser | null;\n context: BrowserContext | null;\n page: Page | null;\n}\n\nfunction findProviderPage(\n browser: Browser,\n provider: BrowserProvider,\n): { context: BrowserContext; page: Page } | null {\n for (const ctx of browser.contexts()) {\n for (const page of ctx.pages()) {\n if (page.url().includes(provider.origin)) return { context: ctx, page };\n }\n }\n return null;\n}\n\nasync function navigateIfNeeded(page: Page, provider: BrowserProvider): Promise<void> {\n wireSafeDialogHandlers(page);\n if (!page.url().includes(provider.origin)) {\n await page.goto(provider.defaultUrl, { waitUntil: \"domcontentloaded\" });\n }\n await page.waitForSelector(provider.composerSelector, { timeout: 30_000 }).catch(() => {});\n}\n\n/** Dismiss JS alerts/confirms without crashing when CDP races Playwright's dialog manager. */\nfunction wireSafeDialogHandlers(page: Page): void {\n if ((page as Page & { __bridgeDialogWired?: boolean }).__bridgeDialogWired) return;\n (page as Page & { __bridgeDialogWired?: boolean }).__bridgeDialogWired = true;\n page.on(\"dialog\", (dialog) => {\n void dialog.dismiss().catch(() => undefined);\n });\n}\n\nfunction wireSafeDialogHandlersForContext(context: BrowserContext): void {\n for (const page of context.pages()) wireSafeDialogHandlers(page);\n context.on(\"page\", (page) => wireSafeDialogHandlers(page));\n}\n\nfunction interceptResponses(\n context: BrowserContext,\n providerId: string,\n conversations: Conversation[],\n): void {\n context.on(\"response\", (response: Response) => {\n if (providerId !== \"chatgpt\") return;\n void parseChatGptConversations(response, conversations).catch(() => {});\n });\n}\n\nasync function parseChatGptConversations(\n response: Response,\n conversations: Conversation[],\n): Promise<void> {\n const url = response.url();\n if (!url.includes(\"/backend-api/conversations?\")) return;\n const body = await response.json().catch(() => null);\n const items = body?.items;\n if (!Array.isArray(items)) return;\n conversations.splice(\n 0,\n conversations.length,\n ...items.map((item: Record<string, unknown>) => ({\n id: String(item.id),\n title: String(item.title ?? \"Untitled\"),\n url: `https://chatgpt.com/c/${item.id}`,\n })),\n );\n}\n\nasync function tryConnectOverCdp(input: {\n state: CdpConnectState;\n provider: BrowserProvider;\n attempts?: number;\n intervalMs?: number;\n isPortListening: () => Promise<boolean>;\n close: () => Promise<void>;\n}): Promise<boolean> {\n const attempts = input.attempts ?? 8;\n const intervalMs = input.intervalMs ?? 400;\n for (let i = 0; i < attempts; i++) {\n if (!(await input.isPortListening())) {\n if (i < attempts - 1) await sleep(intervalMs);\n continue;\n }\n if (await connectOnceOverCdp(input)) return true;\n if (i < attempts - 1) await sleep(intervalMs);\n }\n return false;\n}\n\nasync function connectOnceOverCdp(input: {\n state: CdpConnectState;\n provider: BrowserProvider;\n close: () => Promise<void>;\n}): Promise<boolean> {\n try {\n input.state.browser = await chromium.connectOverCDP(CDP_URL);\n const found = findProviderPage(input.state.browser, input.provider);\n if (found) {\n input.state.context = found.context;\n input.state.page = found.page;\n console.error(` Connected to running Chrome, found ${input.provider.origin} tab.`);\n } else {\n const [firstContext] = input.state.browser.contexts();\n if (!firstContext) {\n await input.close();\n return false;\n }\n input.state.context = firstContext;\n input.state.page = await firstContext.newPage();\n console.error(\n ` Connected to running Chrome, no ${input.provider.origin} tab — opening one.`,\n );\n }\n return Boolean(input.state.page);\n } catch {\n await input.close();\n return false;\n }\n}\n\n/** Manages the Playwright browser connected to the bridge Chrome profile. */\nexport class BrowserManager {\n private browser: Browser | null = null;\n private context: BrowserContext | null = null;\n private page: Page | null = null;\n private conversations: Conversation[] = [];\n private readonly providerId: BridgeProviderId;\n private readonly provider: BrowserProvider;\n readonly attachedViaCdp = { value: false };\n readonly spawnedNew = { value: false };\n\n constructor(\n private readonly repoPath: string = process.cwd(),\n providerId: BridgeProviderId = \"chatgpt\",\n ) {\n this.providerId = providerId;\n this.provider = getBrowserProvider(providerId);\n }\n\n /** Launch Chrome or attach to an existing debug session. */\n async launch(): Promise<Page> {\n await this.resetSession();\n prepareProfileDirectories(this.repoPath, this.profileDir());\n if (await this.connectExisting()) return this.markAttached();\n return await this.continueLaunch();\n }\n\n /** Attach to an already-running Chrome debug session without spawning a new window. */\n async attach(opts?: { attempts?: number; intervalMs?: number }): Promise<Page> {\n await this.resetSession();\n prepareProfileDirectories(this.repoPath, this.profileDir());\n if (await isDebugPortListening({ port: BRIDGE_DEBUG_PORT })) {\n const actual = await getUserDataDirOnDebugPort(BRIDGE_DEBUG_PORT);\n const expected = this.profileDir();\n if (actual && !profilesMatch(expected, actual)) {\n throw new BrowserAttachError(\n `Debug port ${BRIDGE_DEBUG_PORT} uses the wrong Chrome profile.\\n Expected: ${expected}\\n Found: ${actual}\\nRun \\`bridge login --repo ${this.repoPath}\\` or close the other Chrome.`,\n );\n }\n }\n if (await this.connectExisting(opts)) return this.markAttached();\n throw attachOnlyError();\n }\n\n /** Return the active Playwright page, or throw if the browser is not launched. */\n getPage(): Page {\n if (!this.page) throw new Error(\"Browser not launched. Call launch() first.\");\n return this.page;\n }\n\n /** Close the browser session and reset internal state. */\n async close(): Promise<void> {\n await this.browser?.close();\n this.page = null;\n this.context = null;\n this.browser = null;\n }\n\n /** Clear any active session before a new launch or attach. */\n private async resetSession(): Promise<void> {\n if (this.context || this.browser) await this.close();\n }\n\n /** Mark the session as attached via CDP and return the active page. */\n private markAttached(): Page {\n this.attachedViaCdp.value = true;\n return this.getPage();\n }\n\n /** Resolve the isolated Chrome profile directory for this repo and provider. */\n private profileDir(): string {\n return chromeProfileDir(this.repoPath, this.providerId);\n }\n\n /** Spawn Chrome or attach when the debug port is already open. */\n private async continueLaunch(): Promise<Page> {\n await this.ensureExpectedProfileOnDebugPort();\n if (await isDebugPortListening({ port: BRIDGE_DEBUG_PORT })) {\n const connected = await this.connectExisting({ attempts: 20, intervalMs: 500 });\n if (connected) return this.getPage();\n throw new BrowserAttachError(\n `Chrome debug port ${BRIDGE_DEBUG_PORT} is open but the bridge could not attach. Close other Chrome windows or run \\`bridge login\\`.`,\n );\n }\n if (await isChromeProcessRunning()) throw chromeAlreadyRunningError();\n return await this.runSpawnAndConnect();\n }\n\n /** Replace a foreign Chrome on :9222, or connect when the signed-in profile is already up. */\n private async ensureExpectedProfileOnDebugPort(): Promise<void> {\n if (!(await isDebugPortListening({ port: BRIDGE_DEBUG_PORT }))) return;\n const expected = this.profileDir();\n const actual = await getUserDataDirOnDebugPort(BRIDGE_DEBUG_PORT);\n if (actual && profilesMatch(expected, actual)) return;\n console.error(\n actual\n ? ` Debug port ${BRIDGE_DEBUG_PORT} has wrong profile — replacing.\\n Expected: ${expected}\\n Found: ${actual}`\n : ` Debug port ${BRIDGE_DEBUG_PORT} is open but profile could not be verified — replacing.`,\n );\n await terminateChromeOnDebugPort(BRIDGE_DEBUG_PORT);\n }\n\n /** Spawn Chrome and wait for a CDP connection. */\n private async runSpawnAndConnect(): Promise<Page> {\n const profileDir = this.profileDir();\n console.error(` Launching bridge Chrome profile: ${profileDir}`);\n spawnChrome(profileDir, this.provider.defaultUrl);\n this.spawnedNew.value = true;\n console.error(\" Waiting for Chrome debug port...\");\n await waitForDebugPort(BRIDGE_DEBUG_PORT);\n const connected = await this.connectExisting({ attempts: 20, intervalMs: 500 });\n if (!connected || !this.page) throw spawnReadyError();\n return this.getPage();\n }\n\n /** Build mutable CDP state for connect helpers. */\n private cdpState(): CdpConnectState {\n return { browser: this.browser, context: this.context, page: this.page };\n }\n\n /** Apply CDP connection results to instance fields. */\n private applyCdpState(state: CdpConnectState): void {\n this.browser = state.browser;\n this.context = state.context;\n this.page = state.page;\n }\n\n /** Retry CDP attach until a provider page is available. */\n private async connectExisting(opts?: {\n attempts?: number;\n intervalMs?: number;\n }): Promise<boolean> {\n const state = this.cdpState();\n const connected = await tryConnectOverCdp({\n state,\n provider: this.provider,\n attempts: opts?.attempts,\n intervalMs: opts?.intervalMs,\n isPortListening: () => isDebugPortListening(),\n close: () => this.close(),\n });\n if (!connected) return false;\n this.finalizeCdpConnection(state);\n return true;\n }\n\n /** Wire response listeners and navigate after a successful CDP attach. */\n private finalizeCdpConnection(state: CdpConnectState): void {\n this.applyCdpState(state);\n const { context, page } = state;\n if (!context || !page) return;\n wireSafeDialogHandlersForContext(context);\n interceptResponses(context, this.providerId, this.conversations);\n void navigateIfNeeded(page, this.provider);\n }\n}\n","import { createHash, randomUUID } from \"node:crypto\";\nimport type { Dirent } from \"node:fs\";\nimport { appendFile, mkdir, readFile, readdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport { hasErrorCode } from \"@/features/domain\";\nimport type { BridgeProviderId } from \"@/features/providers\";\nimport { ensureInsideRepo } from \"@/features/tools\";\n\n// ---------------------------------------------------------------------------\n// Types — session\n// ---------------------------------------------------------------------------\n\n/** ISO timestamp or Date accepted by session store normalizers. */\nexport type TimestampInput = Date | string;\n\n/** Options for session store I/O (base dir, clock, id factory). */\nexport interface SessionStoreOptions {\n baseDir?: string;\n now?: () => Date;\n createId?: () => string;\n}\n\n/** Persisted session metadata. */\nexport interface SessionMetadata {\n id: string;\n repoPath: string;\n model: string | null;\n contextLimit: number;\n tunnelUrl: string | null;\n startedAt: string;\n updatedAt: string;\n}\n\n/** Role of a transcript message event. */\nexport type SessionEventRole = \"user\" | \"assistant\" | \"system\" | \"tool\";\n\n/** One persisted session event (message, action, etc.). */\nexport interface SessionEvent {\n id: string;\n type: string;\n createdAt: string;\n role?: SessionEventRole;\n name?: string;\n status?: string;\n content?: string;\n data?: Record<string, unknown>;\n}\n\n/** Loaded session metadata plus its event log. */\nexport interface SessionRecord {\n metadata: SessionMetadata;\n events: SessionEvent[];\n}\n\n/** Input for {@link SessionStore.createSession}. */\nexport interface CreateSessionInput {\n id?: string;\n repoPath: string;\n model?: string | null;\n contextLimit: number;\n tunnelUrl?: string | null;\n startedAt?: TimestampInput;\n updatedAt?: TimestampInput;\n}\n\n/** Partial metadata patch for {@link updateSession}. */\nexport interface UpdateSessionInput {\n repoPath?: string;\n model?: string | null;\n contextLimit?: number;\n tunnelUrl?: string | null;\n updatedAt?: TimestampInput;\n}\n\n/** Input for {@link SessionStore.appendEvent}. */\nexport interface AppendSessionEventInput {\n id?: string;\n type: string;\n createdAt?: TimestampInput;\n role?: SessionEventRole;\n name?: string;\n status?: string;\n content?: string;\n data?: Record<string, unknown>;\n}\n\n/** Export bundle with human-readable and machine-readable formats. */\nexport interface SessionExport extends SessionRecord {\n transcript: string;\n json: string;\n jsonl: string;\n}\n\n/** Resolved on-disk paths for one session directory. */\ninterface SessionPaths {\n baseDir: string;\n sessionDir: string;\n metadataPath: string;\n eventsPath: string;\n}\n\n// ---------------------------------------------------------------------------\n// Types — checkpoints\n// ---------------------------------------------------------------------------\n\n/** Checkpoint phase relative to a patch operation. */\nexport type CheckpointPhase = \"before\" | \"after\";\n\n/** Snapshot of one file at checkpoint time. */\nexport interface CheckpointFileSnapshot {\n relativePath: string;\n exists: boolean;\n size: number;\n sha256?: string;\n snapshotRef?: string;\n}\n\n/** Full checkpoint record persisted on disk. */\nexport interface Checkpoint {\n id: string;\n repoRoot: string;\n createdAt: string;\n phase: CheckpointPhase;\n label?: string;\n files: CheckpointFileSnapshot[];\n}\n\n/** Summary row returned by {@link listCheckpoints}. */\nexport interface CheckpointSummary {\n id: string;\n createdAt: string;\n phase: CheckpointPhase;\n fileCount: number;\n label?: string;\n}\n\n/** Resolved absolute and relative path inside a repo. */\ninterface RepoPath {\n absolutePath: string;\n relativePath: string;\n}\n\n/** Options for {@link SessionStore.saveCheckpoint}. */\nexport interface CreateCheckpointOptions {\n repoRoot: string;\n paths: readonly string[];\n phase?: CheckpointPhase;\n label?: string;\n checkpointRoot?: string;\n now?: Date;\n}\n\n/** Options for {@link listCheckpoints}. */\nexport interface ListCheckpointsOptions {\n repoRoot: string;\n checkpointRoot?: string;\n}\n\n/** Options for {@link restoreCheckpoint}. */\nexport interface RestoreCheckpointOptions {\n repoRoot: string;\n checkpointId: string;\n checkpointRoot?: string;\n paths?: readonly string[];\n}\n\n/** Result of {@link restoreCheckpoint}. */\nexport interface RestoreCheckpointResult {\n checkpointId: string;\n restored: string[];\n removed: string[];\n}\n\ninterface CheckpointIdInput {\n repoRoot: string;\n createdAt: string;\n phase: CheckpointPhase;\n label?: string;\n paths: readonly string[];\n}\n\ninterface CreateCheckpointBuildContext {\n repoRoot: string;\n createdAt: string;\n phase: CheckpointPhase;\n label?: string;\n resolvedPaths: RepoPath[];\n checkpointDir: string;\n filesDir: string;\n id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Types — file resolver & logging\n// ---------------------------------------------------------------------------\n\n/** Result of resolving a single @file mention. */\nexport interface ResolvedFile {\n relPath: string;\n content: string;\n}\n\nexport interface BridgeLogEvent {\n repoPath: string;\n type: string;\n data?: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst METADATA_FILE = \"metadata.json\";\nconst EVENTS_FILE = \"events.jsonl\";\nconst SAFE_SESSION_ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\nconst FILE_MENTION_RE = /@([\\w./_-]+(?:\\.[\\w]+))/g;\n\n/** Repo-local bridge directory name (e.g. `<repo>/.bridge`). */\nexport const REPO_DIR_NAME = \".bridge\";\n\n/** Machine-global home directory name for user-authored cross-repo config. */\nexport const BRIDGE_DIR_NAME = \".ai-browser-bridge\";\n\n/** Filename for hook config shared by repo and home directories. */\nexport const HOOKS_FILE = \"hooks.json\";\n\n// ---------------------------------------------------------------------------\n// Path helpers\n// ---------------------------------------------------------------------------\n\n/** Absolute repo-local `.bridge` directory for a target repo. */\nexport function bridgeDir(repoPath: string): string {\n return join(repoPath, REPO_DIR_NAME);\n}\n\n/** Per-repo persisted config file. */\nexport function configPath(repoPath: string): string {\n return join(bridgeDir(repoPath), \"config.json\");\n}\n\n/** Per-repo bridge activity log directory. */\nexport function logsDir(repoPath: string): string {\n return join(bridgeDir(repoPath), \"logs\");\n}\n\n/** Per-repo session store directory. */\nexport function sessionsDir(repoPath: string): string {\n return join(bridgeDir(repoPath), \"sessions\");\n}\n\n/** Per-repo checkpoint store for MCP-patch rollbacks. */\nexport function checkpointsDir(repoPath: string): string {\n return join(bridgeDir(repoPath), \"checkpoints\");\n}\n\n/** Per-repo default location for `/export` output. */\nexport function exportsDir(repoPath: string): string {\n return join(bridgeDir(repoPath), \"exports\");\n}\n\n/** Per-repo screenshot output directory. */\nexport function screenshotsDir(repoPath: string): string {\n return join(bridgeDir(repoPath), \"screenshots\");\n}\n\ninterface ChromeProfileInput {\n repoPath: string;\n provider?: BridgeProviderId;\n}\n\n/** Isolated Chrome user-data directory for the signed-in provider session. */\nexport function chromeProfileDir(\n input: ChromeProfileInput | string,\n provider: BridgeProviderId = \"chatgpt\",\n): string {\n const repoPath = typeof input === \"string\" ? input : input.repoPath;\n const providerId = typeof input === \"string\" ? provider : (input.provider ?? \"chatgpt\");\n const dirName = providerId === \"gemini\" ? \"chrome-profile-gemini\" : \"chrome-profile\";\n return join(bridgeDir(repoPath), dirName);\n}\n\n/** Create `<repo>/.bridge` and assert its self-ignoring `.gitignore`. */\nexport async function ensureBridgeDir(repoPath: string): Promise<string> {\n const dir = bridgeDir(repoPath);\n await mkdir(dir, { recursive: true });\n await writeFile(join(dir, \".gitignore\"), \"*\\n\", \"utf-8\");\n return dir;\n}\n\n/** Absolute machine-global bridge home for a given OS home directory. */\nexport function bridgeHome(home = homedir()): string {\n return join(home, BRIDGE_DIR_NAME);\n}\n\n/** Path to the user-level hooks config, honouring an injected home dir for tests. */\nexport function homeHooksPath(home = homedir()): string {\n return join(bridgeHome(home), HOOKS_FILE);\n}\n\n/** Default sessions directory for the current working directory. */\nexport function defaultSessionStoreDir(): string {\n return sessionsDir(process.cwd());\n}\n\nfunction resolveBaseDir(options: SessionStoreOptions): string {\n return options.baseDir ?? defaultSessionStoreDir();\n}\n\nfunction sessionPaths(id: string, options: SessionStoreOptions): SessionPaths {\n const safeId = normalizeSessionId(id);\n const baseDir = resolveBaseDir(options);\n const sessionDir = join(baseDir, safeId);\n return {\n baseDir,\n sessionDir,\n metadataPath: join(sessionDir, METADATA_FILE),\n eventsPath: join(sessionDir, EVENTS_FILE),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Session normalizers\n// ---------------------------------------------------------------------------\n\nfunction getNow(options: SessionStoreOptions): () => Date {\n return options.now ?? (() => new Date());\n}\n\nfunction getCreateId(options: SessionStoreOptions): () => string {\n return options.createId ?? randomUUID;\n}\n\nfunction normalizeSessionId(id: string): string {\n if (!SAFE_SESSION_ID.test(id)) throw new Error(`Invalid session id: ${id}`);\n return id;\n}\n\nfunction normalizeSessionEventId(id: string): string {\n if (id.length === 0 || id.includes(\"\\n\") || id.includes(\"\\r\")) {\n throw new Error(\"Invalid session event id\");\n }\n return id;\n}\n\nfunction normalizeTimestamp(value: TimestampInput): string {\n const timestamp = value instanceof Date ? value.toISOString() : value;\n if (Number.isNaN(Date.parse(timestamp))) throw new Error(`Invalid timestamp: ${timestamp}`);\n return timestamp;\n}\n\nfunction latestTimestamp(left: string, right: string): string {\n return Date.parse(left) >= Date.parse(right) ? left : right;\n}\n\nfunction normalizeContextLimit(value: number): number {\n if (!Number.isFinite(value) || value <= 0) throw new Error(`Invalid context limit: ${value}`);\n return value;\n}\n\nfunction normalizeRole(role: string, source: string): SessionEventRole {\n if (role === \"user\" || role === \"assistant\" || role === \"system\" || role === \"tool\") return role;\n throw new Error(`Invalid role in ${source}: ${role}`);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction readString(record: Record<string, unknown>, key: string, source: string): string {\n const value = record[key];\n if (typeof value !== \"string\") throw new Error(`Expected ${key} to be a string in ${source}`);\n return value;\n}\n\nfunction readOptionalString(\n record: Record<string, unknown>,\n key: string,\n source: string,\n): string | undefined {\n const value = record[key];\n if (value === undefined) return undefined;\n if (typeof value !== \"string\") throw new Error(`Expected ${key} to be a string in ${source}`);\n return value;\n}\n\nfunction readNullableString(\n record: Record<string, unknown>,\n key: string,\n source: string,\n): string | null {\n const value = record[key];\n if (value === null) return null;\n if (typeof value !== \"string\")\n throw new Error(`Expected ${key} to be a string or null in ${source}`);\n return value;\n}\n\nfunction readNumber(record: Record<string, unknown>, key: string, source: string): number {\n const value = record[key];\n if (typeof value !== \"number\") throw new Error(`Expected ${key} to be a number in ${source}`);\n return value;\n}\n\nfunction parseJsonObject(raw: string, source: string): Record<string, unknown> {\n const parsed: unknown = JSON.parse(raw);\n if (!isRecord(parsed)) throw new Error(`Expected JSON object in ${source}`);\n return parsed;\n}\n\n// ---------------------------------------------------------------------------\n// Session deserialize\n// ---------------------------------------------------------------------------\n\nfunction metadataFromObject(record: Record<string, unknown>, source: string): SessionMetadata {\n return {\n id: normalizeSessionId(readString(record, \"id\", source)),\n repoPath: readString(record, \"repoPath\", source),\n model: readNullableString(record, \"model\", source),\n contextLimit: normalizeContextLimit(readNumber(record, \"contextLimit\", source)),\n tunnelUrl: readNullableString(record, \"tunnelUrl\", source),\n startedAt: normalizeTimestamp(readString(record, \"startedAt\", source)),\n updatedAt: normalizeTimestamp(readString(record, \"updatedAt\", source)),\n };\n}\n\nfunction applyOptionalEventFields(\n event: SessionEvent,\n record: Record<string, unknown>,\n source: string,\n): void {\n const role = readOptionalString(record, \"role\", source);\n if (role !== undefined) event.role = normalizeRole(role, source);\n for (const field of [\"name\", \"status\", \"content\"] as const) {\n const value = readOptionalString(record, field, source);\n if (value !== undefined) event[field] = value;\n }\n const data = record.data;\n if (data === undefined) return;\n if (!isRecord(data)) throw new Error(`Expected data to be an object in ${source}`);\n event.data = data;\n}\n\nfunction eventFromObject(record: Record<string, unknown>, source: string): SessionEvent {\n const event: SessionEvent = {\n id: readString(record, \"id\", source),\n type: readString(record, \"type\", source),\n createdAt: normalizeTimestamp(readString(record, \"createdAt\", source)),\n };\n applyOptionalEventFields(event, record, source);\n return event;\n}\n\n// ---------------------------------------------------------------------------\n// Session read / write\n// ---------------------------------------------------------------------------\n\nasync function readMetadata(path: string): Promise<SessionMetadata> {\n const raw = await readFile(path, \"utf-8\");\n return metadataFromObject(parseJsonObject(raw, path), path);\n}\n\nasync function readRawEvents(path: string): Promise<string> {\n try {\n return await readFile(path, \"utf-8\");\n } catch (error) {\n if (hasErrorCode(error, \"ENOENT\")) return \"\";\n throw error;\n }\n}\n\nfunction parseEventLine(line: string, path: string): SessionEvent {\n const source = `${path}:${line.length}`;\n return eventFromObject(parseJsonObject(line, source), source);\n}\n\nasync function readEvents(path: string): Promise<SessionEvent[]> {\n const raw = await readRawEvents(path);\n if (raw.trim().length === 0) return [];\n return raw\n .split(/\\r?\\n/)\n .filter((line) => line.trim().length > 0)\n .map((line) => parseEventLine(line, path));\n}\n\nasync function writeMetadata(path: string, metadata: SessionMetadata): Promise<void> {\n await writeFile(path, `${JSON.stringify(metadata, null, 2)}\\n`, \"utf-8\");\n}\n\nasync function readSessionDirEntries(baseDir: string): Promise<Dirent[]> {\n try {\n return await readdir(baseDir, { withFileTypes: true });\n } catch (error) {\n if (hasErrorCode(error, \"ENOENT\")) return [];\n throw error;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Session build / update / list\n// ---------------------------------------------------------------------------\n\nfunction buildSessionMetadata(\n input: CreateSessionInput,\n options: SessionStoreOptions,\n): SessionMetadata {\n const id = normalizeSessionId(input.id ?? getCreateId(options)());\n const startedAt = normalizeTimestamp(input.startedAt ?? getNow(options)());\n const updatedAt = normalizeTimestamp(input.updatedAt ?? startedAt);\n return {\n id,\n repoPath: input.repoPath,\n model: input.model ?? null,\n contextLimit: normalizeContextLimit(input.contextLimit),\n tunnelUrl: input.tunnelUrl ?? null,\n startedAt,\n updatedAt,\n };\n}\n\nfunction buildSessionEvent(\n input: AppendSessionEventInput,\n options: SessionStoreOptions,\n): SessionEvent {\n return {\n id: normalizeSessionEventId(input.id ?? getCreateId(options)()),\n type: input.type,\n createdAt: normalizeTimestamp(input.createdAt ?? getNow(options)()),\n ...(input.role ? { role: input.role } : {}),\n ...(input.name !== undefined ? { name: input.name } : {}),\n ...(input.status !== undefined ? { status: input.status } : {}),\n ...(input.content !== undefined ? { content: input.content } : {}),\n ...(input.data !== undefined ? { data: input.data } : {}),\n };\n}\n\nfunction mergeSessionMetadata(\n current: SessionMetadata,\n input: UpdateSessionInput,\n options: SessionStoreOptions,\n): SessionMetadata {\n return {\n ...current,\n ...(input.repoPath !== undefined ? { repoPath: input.repoPath } : {}),\n ...(input.model !== undefined ? { model: input.model } : {}),\n ...(input.contextLimit !== undefined\n ? { contextLimit: normalizeContextLimit(input.contextLimit) }\n : {}),\n ...(input.tunnelUrl !== undefined ? { tunnelUrl: input.tunnelUrl } : {}),\n updatedAt: normalizeTimestamp(input.updatedAt ?? getNow(options)()),\n };\n}\n\nasync function initSessionDir(\n metadata: SessionMetadata,\n options: SessionStoreOptions,\n): Promise<void> {\n const paths = sessionPaths(metadata.id, options);\n await mkdir(paths.baseDir, { recursive: true });\n await mkdir(paths.sessionDir);\n await writeMetadata(paths.metadataPath, metadata);\n await writeFile(paths.eventsPath, \"\", \"utf-8\");\n}\n\nasync function persistAppendedEvent(input: {\n paths: SessionPaths;\n metadata: SessionMetadata;\n event: SessionEvent;\n}): Promise<void> {\n await appendFile(input.paths.eventsPath, `${JSON.stringify(input.event)}\\n`, \"utf-8\");\n await writeMetadata(input.paths.metadataPath, {\n ...input.metadata,\n updatedAt: latestTimestamp(input.metadata.updatedAt, input.event.createdAt),\n });\n}\n\nasync function tryReadSessionMetadata(\n baseDir: string,\n entry: Dirent,\n): Promise<SessionMetadata | null> {\n if (!entry.isDirectory() || !SAFE_SESSION_ID.test(entry.name)) return null;\n try {\n return await readMetadata(join(baseDir, entry.name, METADATA_FILE));\n } catch (error) {\n if (hasErrorCode(error, \"ENOENT\")) return null;\n throw error;\n }\n}\n\nasync function collectSessionMetadata(\n baseDir: string,\n entries: Dirent[],\n): Promise<SessionMetadata[]> {\n const sessions: SessionMetadata[] = [];\n for (const entry of entries) {\n const metadata = await tryReadSessionMetadata(baseDir, entry);\n if (metadata) sessions.push(metadata);\n }\n return sessions;\n}\n\nfunction sortSessionsByActivity(sessions: SessionMetadata[]): SessionMetadata[] {\n return sessions.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));\n}\n\n// ---------------------------------------------------------------------------\n// Session transcript / export\n// ---------------------------------------------------------------------------\n\nfunction eventDetail(event: SessionEvent): string {\n return event.content ?? (event.data ? JSON.stringify(event.data) : \"\");\n}\n\nfunction formatTranscriptEvent(event: SessionEvent): string {\n const prefix = `[${event.createdAt}]`;\n if (event.type === \"message\")\n return `${prefix} ${event.role ?? \"message\"}: ${event.content ?? \"\"}`;\n if (event.type === \"action\") {\n const name = event.name ? ` ${event.name}` : \"\";\n const status = event.status ? ` ${event.status}` : \"\";\n const detail = eventDetail(event);\n return detail\n ? `${prefix} action${name}${status}: ${detail}`\n : `${prefix} action${name}${status}`;\n }\n const label = [event.type, event.name, event.status].filter(Boolean).join(\" \");\n const detail = eventDetail(event);\n return detail ? `${prefix} ${label}: ${detail}` : `${prefix} ${label}`;\n}\n\nfunction formatTranscript(events: SessionEvent[]): string {\n return events.map(formatTranscriptEvent).join(\"\\n\");\n}\n\nasync function loadSessionRecord(\n sessionId: string,\n options: SessionStoreOptions,\n): Promise<SessionRecord> {\n const paths = sessionPaths(sessionId, options);\n return {\n metadata: await readMetadata(paths.metadataPath),\n events: await readEvents(paths.eventsPath),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Checkpoint helpers\n// ---------------------------------------------------------------------------\n\nfunction sha256(input: string | Buffer): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction toPosixPath(path: string): string {\n return path.split(sep).join(\"/\");\n}\n\nfunction checkpointStorageRoot(\n repoRoot: string,\n checkpointRoot = checkpointsDir(repoRoot),\n): string {\n return join(checkpointRoot, sha256(resolve(repoRoot)).slice(0, 16));\n}\n\nfunction checkpointMetadataPath(checkpointDir: string): string {\n return join(checkpointDir, \"checkpoint.json\");\n}\n\nfunction resolveRepoPath(repoRoot: string, path: string): RepoPath {\n const normalizedRoot = resolve(repoRoot);\n const absolutePath = resolve(normalizedRoot, path);\n if (absolutePath !== normalizedRoot && !absolutePath.startsWith(normalizedRoot + sep)) {\n throw new Error(`Path escapes repo root: ${path}`);\n }\n return {\n absolutePath,\n relativePath: toPosixPath(relative(normalizedRoot, absolutePath) || \".\"),\n };\n}\n\nfunction resolveInside(root: string, path: string): string {\n const normalizedRoot = resolve(root);\n const resolved = resolve(normalizedRoot, path);\n if (resolved !== normalizedRoot && !resolved.startsWith(normalizedRoot + sep)) {\n throw new Error(`Path escapes checkpoint store: ${path}`);\n }\n return resolved;\n}\n\nfunction uniquePaths(paths: readonly string[]): string[] {\n return [...new Set(paths)];\n}\n\nfunction checkpointId(input: CheckpointIdInput): string {\n const timestamp = input.createdAt.replace(/[:.]/g, \"-\");\n const digest = sha256(JSON.stringify(input)).slice(0, 12);\n return `${timestamp}-${input.phase}-${digest}`;\n}\n\nfunction defaultPhase(phase?: CheckpointPhase): CheckpointPhase {\n return phase ?? \"before\";\n}\n\nfunction buildCheckpointPaths(ctx: {\n repoRoot: string;\n createdAt: string;\n phase: CheckpointPhase;\n label?: string;\n resolvedPaths: RepoPath[];\n checkpointRoot?: string;\n}) {\n const id = checkpointId({\n repoRoot: ctx.repoRoot,\n createdAt: ctx.createdAt,\n phase: ctx.phase,\n label: ctx.label,\n paths: ctx.resolvedPaths.map((entry) => entry.relativePath),\n });\n const checkpointDir = join(checkpointStorageRoot(ctx.repoRoot, ctx.checkpointRoot), id);\n return { id, checkpointDir, filesDir: join(checkpointDir, \"files\") };\n}\n\nfunction buildCreateCheckpointContext(\n options: CreateCheckpointOptions,\n): CreateCheckpointBuildContext {\n const repoRoot = resolve(options.repoRoot);\n const phase = defaultPhase(options.phase);\n const createdAt = (options.now ?? new Date()).toISOString();\n const resolvedPaths = uniquePaths(options.paths).map((path) => resolveRepoPath(repoRoot, path));\n const base = { repoRoot, createdAt, phase, label: options.label, resolvedPaths };\n return { ...base, ...buildCheckpointPaths({ ...base, checkpointRoot: options.checkpointRoot }) };\n}\n\nfunction buildCheckpointRecord(\n ctx: CreateCheckpointBuildContext,\n files: Checkpoint[\"files\"],\n): Checkpoint {\n return {\n id: ctx.id,\n repoRoot: ctx.repoRoot,\n createdAt: ctx.createdAt,\n phase: ctx.phase,\n label: ctx.label,\n files,\n };\n}\n\nfunction buildSelectedPaths(\n repoRoot: string,\n paths: readonly string[] | undefined,\n): Set<string> | undefined {\n if (!paths) return undefined;\n return new Set(paths.map((path) => resolveRepoPath(repoRoot, path).relativePath));\n}\n\nasync function tryStat(repoPath: RepoPath) {\n try {\n return await stat(repoPath.absolutePath);\n } catch (error) {\n if (hasErrorCode(error, \"ENOENT\")) return undefined;\n throw error;\n }\n}\n\nasync function writeFileSnapshot(\n repoPath: RepoPath,\n filesDir: string,\n fileStat: Awaited<ReturnType<typeof stat>>,\n): Promise<CheckpointFileSnapshot> {\n const contents = await readFile(repoPath.absolutePath);\n const contentHash = sha256(contents);\n const snapshotRef = `${contentHash}-${sha256(repoPath.relativePath).slice(0, 12)}`;\n await writeFile(join(filesDir, snapshotRef), contents);\n return {\n relativePath: repoPath.relativePath,\n exists: true,\n size: Number(fileStat.size),\n sha256: contentHash,\n snapshotRef,\n };\n}\n\nasync function snapshotFile(repoPath: RepoPath, filesDir: string): Promise<CheckpointFileSnapshot> {\n const fileStat = await tryStat(repoPath);\n if (!fileStat) return { relativePath: repoPath.relativePath, exists: false, size: 0 };\n if (fileStat.isDirectory())\n throw new Error(`Cannot checkpoint directory: ${repoPath.relativePath}`);\n if (!fileStat.isFile())\n throw new Error(`Cannot checkpoint non-file path: ${repoPath.relativePath}`);\n return writeFileSnapshot(repoPath, filesDir, fileStat);\n}\n\nasync function readCheckpoint(checkpointDir: string): Promise<Checkpoint | undefined> {\n try {\n return JSON.parse(await readFile(checkpointMetadataPath(checkpointDir), \"utf-8\")) as Checkpoint;\n } catch (error) {\n if (hasErrorCode(error, \"ENOENT\")) return undefined;\n throw error;\n }\n}\n\nasync function writeCheckpointFiles(\n ctx: CreateCheckpointBuildContext,\n): Promise<Checkpoint[\"files\"]> {\n await mkdir(ctx.filesDir, { recursive: true });\n const files = [];\n for (const repoPath of ctx.resolvedPaths) files.push(await snapshotFile(repoPath, ctx.filesDir));\n return files;\n}\n\nasync function persistCheckpoint(\n ctx: CreateCheckpointBuildContext,\n files: Checkpoint[\"files\"],\n): Promise<Checkpoint> {\n const checkpoint = buildCheckpointRecord(ctx, files);\n await writeFile(\n checkpointMetadataPath(ctx.checkpointDir),\n JSON.stringify(checkpoint, null, 2),\n \"utf-8\",\n );\n return checkpoint;\n}\n\nasync function readCheckpointDirEntries(storeRoot: string): Promise<Dirent[]> {\n try {\n return await readdir(storeRoot, { withFileTypes: true });\n } catch (error) {\n if (hasErrorCode(error, \"ENOENT\")) return [];\n throw error;\n }\n}\n\nasync function tryReadCheckpointSummary(\n storeRoot: string,\n entry: Dirent,\n): Promise<CheckpointSummary | null> {\n if (!entry.isDirectory()) return null;\n const checkpoint = await readCheckpoint(join(storeRoot, entry.name));\n if (!checkpoint) return null;\n return {\n id: checkpoint.id,\n createdAt: checkpoint.createdAt,\n phase: checkpoint.phase,\n label: checkpoint.label,\n fileCount: checkpoint.files.length,\n };\n}\n\nasync function collectCheckpointSummaries(\n storeRoot: string,\n entries: Dirent[],\n): Promise<CheckpointSummary[]> {\n const checkpoints: CheckpointSummary[] = [];\n for (const entry of entries) {\n const summary = await tryReadCheckpointSummary(storeRoot, entry);\n if (summary) checkpoints.push(summary);\n }\n return checkpoints;\n}\n\nfunction sortCheckpointSummaries(checkpoints: CheckpointSummary[]): CheckpointSummary[] {\n return checkpoints.sort(\n (left, right) =>\n right.createdAt.localeCompare(left.createdAt) || right.id.localeCompare(left.id),\n );\n}\n\nasync function restoreExistingFile(input: {\n repoRoot: string;\n checkpointDir: string;\n file: CheckpointFileSnapshot;\n target: RepoPath;\n restored: string[];\n}): Promise<void> {\n if (!input.file.snapshotRef)\n throw new Error(`Checkpoint file is missing snapshot data: ${input.file.relativePath}`);\n const snapshotPath = resolveInside(input.checkpointDir, join(\"files\", input.file.snapshotRef));\n const contents = await readFile(snapshotPath);\n await mkdir(dirname(input.target.absolutePath), { recursive: true });\n await writeFile(input.target.absolutePath, contents);\n input.restored.push(input.target.relativePath);\n}\n\nasync function restoreFile(input: {\n repoRoot: string;\n checkpointDir: string;\n file: CheckpointFileSnapshot;\n restored: string[];\n removed: string[];\n}): Promise<void> {\n const target = resolveRepoPath(input.repoRoot, input.file.relativePath);\n if (input.file.exists) {\n await restoreExistingFile({ ...input, target });\n return;\n }\n await rm(target.absolutePath, { force: true });\n input.removed.push(target.relativePath);\n}\n\nfunction validateSelectedPaths(\n checkpoint: Checkpoint,\n selectedPaths: Set<string> | undefined,\n): void {\n if (!selectedPaths) return;\n for (const selectedPath of selectedPaths) {\n if (!checkpoint.files.some((file) => file.relativePath === selectedPath)) {\n throw new Error(`Checkpoint does not include path: ${selectedPath}`);\n }\n }\n}\n\nasync function restoreAllFiles(input: {\n repoRoot: string;\n checkpointDir: string;\n checkpoint: Checkpoint;\n selectedPaths: Set<string> | undefined;\n}): Promise<RestoreCheckpointResult> {\n const restored: string[] = [];\n const removed: string[] = [];\n for (const file of input.checkpoint.files) {\n if (input.selectedPaths && !input.selectedPaths.has(file.relativePath)) continue;\n await restoreFile({\n repoRoot: input.repoRoot,\n checkpointDir: input.checkpointDir,\n file,\n restored,\n removed,\n });\n }\n validateSelectedPaths(input.checkpoint, input.selectedPaths);\n return { checkpointId: input.checkpoint.id, restored, removed };\n}\n\n// ---------------------------------------------------------------------------\n// File resolver\n// ---------------------------------------------------------------------------\n\nasync function readMentionContent(absPath: string, rawPath: string): Promise<string> {\n try {\n const fileStat = await stat(absPath);\n if (!fileStat.isFile()) return `[not a file: ${rawPath}]`;\n if (fileStat.size > 100_000) return `[file too large: ${fileStat.size} bytes, max 100000]`;\n return await readFile(absPath, \"utf-8\");\n } catch {\n return `[file not found: ${rawPath}]`;\n }\n}\n\nfunction buildMentionResult(input: {\n prompt: string;\n match: string;\n relPath: string;\n content: string;\n}) {\n const block = `\\n--- @${input.relPath} ---\\n${input.content}\\n--- end @${input.relPath} ---\\n`;\n return {\n prompt: input.prompt.replace(input.match, block),\n file: { relPath: input.relPath, content: input.content },\n };\n}\n\nasync function resolveOneFileMention(input: {\n match: RegExpMatchArray;\n repoRoot: string;\n prompt: string;\n}): Promise<{ prompt: string; file?: ResolvedFile }> {\n const rawPath = input.match[1];\n if (rawPath === undefined) return { prompt: input.prompt };\n const absPath = resolve(input.repoRoot, rawPath);\n const relPath = relative(input.repoRoot, absPath);\n try {\n ensureInsideRepo(absPath, input.repoRoot);\n } catch {\n return { prompt: input.prompt };\n }\n const content = await readMentionContent(absPath, rawPath);\n return buildMentionResult({ prompt: input.prompt, match: input.match[0], relPath, content });\n}\n\nasync function resolveAllFileMentions(input: {\n input: string;\n repoRoot: string;\n matches: RegExpMatchArray[];\n}): Promise<{ prompt: string; files: ResolvedFile[] }> {\n const files: ResolvedFile[] = [];\n let prompt = input.input;\n for (const match of input.matches) {\n const result = await resolveOneFileMention({ match, repoRoot: input.repoRoot, prompt });\n prompt = result.prompt;\n if (result.file) files.push(result.file);\n }\n return { prompt, files };\n}\n\n// ---------------------------------------------------------------------------\n// Logging\n// ---------------------------------------------------------------------------\n\nfunction formatLocalDate(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n\n/** Return today's bridge log path for a repo. */\nexport function bridgeLogPath(repoPath: string, date = new Date()): string {\n return join(logsDir(repoPath), `${formatLocalDate(date)}.jsonl`);\n}\n\n/** Append one JSONL event to the repo's local bridge log. */\nexport async function appendBridgeLog(event: BridgeLogEvent): Promise<void> {\n await mkdir(logsDir(event.repoPath), { recursive: true });\n const line = JSON.stringify({\n ts: new Date().toISOString(),\n repoPath: event.repoPath,\n type: event.type,\n data: event.data ?? {},\n });\n await appendFile(bridgeLogPath(event.repoPath), `${line}\\n`, \"utf-8\");\n}\n\n// ---------------------------------------------------------------------------\n// SessionStore\n// ---------------------------------------------------------------------------\n\n/** Persistent session and checkpoint store for bridge conversations. */\nexport class SessionStore {\n constructor(private readonly options: SessionStoreOptions = {}) {}\n\n /** Create a new session directory with empty event log. */\n async createSession(input: CreateSessionInput): Promise<SessionRecord> {\n const metadata = buildSessionMetadata(input, this.options);\n await initSessionDir(metadata, this.options);\n return { metadata, events: [] };\n }\n\n /** Load session metadata and events from disk. */\n async loadSession(id: string): Promise<SessionRecord> {\n const paths = sessionPaths(id, this.options);\n return {\n metadata: await readMetadata(paths.metadataPath),\n events: await readEvents(paths.eventsPath),\n };\n }\n\n /** List all sessions sorted by most recent activity. */\n async listSessions(): Promise<SessionMetadata[]> {\n const baseDir = resolveBaseDir(this.options);\n const sessions = await collectSessionMetadata(baseDir, await readSessionDirEntries(baseDir));\n return sortSessionsByActivity(sessions);\n }\n\n /** Snapshot the current state of repo files before or after a patch. */\n async saveCheckpoint(options: CreateCheckpointOptions): Promise<Checkpoint> {\n const ctx = buildCreateCheckpointContext(options);\n const files = await writeCheckpointFiles(ctx);\n return persistCheckpoint(ctx, files);\n }\n\n /** Append one event to a session's JSONL log and bump `updatedAt`. */\n async appendEvent(sessionId: string, input: AppendSessionEventInput): Promise<SessionEvent> {\n const paths = sessionPaths(sessionId, this.options);\n const metadata = await readMetadata(paths.metadataPath);\n const event = buildSessionEvent(input, this.options);\n await persistAppendedEvent({ paths, metadata, event });\n return event;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Backward-compatible function exports\n// ---------------------------------------------------------------------------\n\n/** Create a new session directory with empty event log. */\nexport async function createSession(\n input: CreateSessionInput,\n options: SessionStoreOptions = {},\n): Promise<SessionRecord> {\n return new SessionStore(options).createSession(input);\n}\n\n/** Load session metadata and events from disk. */\nexport async function loadSession(\n id: string,\n options: SessionStoreOptions = {},\n): Promise<SessionRecord> {\n return new SessionStore(options).loadSession(id);\n}\n\n/** List all sessions sorted by most recent activity. */\nexport async function listSessions(options: SessionStoreOptions = {}): Promise<SessionMetadata[]> {\n return new SessionStore(options).listSessions();\n}\n\n/** Append one event to a session's JSONL log and bump `updatedAt`. */\nexport async function appendSessionEvent(\n sessionId: string,\n input: AppendSessionEventInput,\n options: SessionStoreOptions = {},\n): Promise<SessionEvent> {\n return new SessionStore(options).appendEvent(sessionId, input);\n}\n\n/** Patch session metadata on disk. */\nexport async function updateSession(\n sessionId: string,\n input: UpdateSessionInput,\n options: SessionStoreOptions = {},\n): Promise<SessionMetadata> {\n const paths = sessionPaths(sessionId, options);\n const next = mergeSessionMetadata(await readMetadata(paths.metadataPath), input, options);\n await writeMetadata(paths.metadataPath, next);\n return next;\n}\n\n/** Export a session with transcript, JSON, and JSONL formats. */\nexport async function exportSession(\n sessionId: string,\n options: SessionStoreOptions = {},\n): Promise<SessionExport> {\n const record = await loadSessionRecord(sessionId, options);\n const jsonl = await readRawEvents(sessionPaths(sessionId, options).eventsPath);\n return {\n ...record,\n transcript: formatTranscript(record.events),\n json: `${JSON.stringify(record, null, 2)}\\n`,\n jsonl,\n };\n}\n\n/** Return the most recently updated session, or null when none exist. */\nexport async function getLatestSession(\n options: SessionStoreOptions = {},\n): Promise<SessionRecord | null> {\n const baseDir = resolveBaseDir(options);\n const entries = await readSessionDirEntries(baseDir);\n const [latest] = sortSessionsByActivity(await collectSessionMetadata(baseDir, entries));\n if (!latest) return null;\n const paths = sessionPaths(latest.id, options);\n return { metadata: latest, events: await readEvents(paths.eventsPath) };\n}\n\n/** Snapshot the current state of repo files before or after a patch. */\nexport async function createCheckpoint(options: CreateCheckpointOptions): Promise<Checkpoint> {\n return new SessionStore().saveCheckpoint(options);\n}\n\n/** List checkpoints for a repository. */\nexport async function listCheckpoints(\n options: ListCheckpointsOptions,\n): Promise<CheckpointSummary[]> {\n const storeRoot = checkpointStorageRoot(options.repoRoot, options.checkpointRoot);\n const summaries = await collectCheckpointSummaries(\n storeRoot,\n await readCheckpointDirEntries(storeRoot),\n );\n return sortCheckpointSummaries(summaries);\n}\n\n/** Restore all or selected files from a checkpoint. */\nexport async function restoreCheckpoint(\n options: RestoreCheckpointOptions,\n): Promise<RestoreCheckpointResult> {\n const repoRoot = resolve(options.repoRoot);\n const checkpointDir = join(\n checkpointStorageRoot(repoRoot, options.checkpointRoot),\n options.checkpointId,\n );\n const checkpoint = await readCheckpoint(checkpointDir);\n if (!checkpoint) throw new Error(`Checkpoint not found: ${options.checkpointId}`);\n return restoreAllFiles({\n repoRoot,\n checkpointDir,\n checkpoint,\n selectedPaths: buildSelectedPaths(repoRoot, options.paths),\n });\n}\n\n/** Extract repo-relative @file mentions from terminal input. */\nexport function extractFileMentions(input: string): string[] {\n const mentions = [...input.matchAll(FILE_MENTION_RE)]\n .map((match) => match[1])\n .filter((mention): mention is string => mention !== undefined);\n return [...new Set(mentions)];\n}\n\n/**\n * Parse @file mentions from user input and resolve them to file contents.\n * Returns the processed prompt with file contents injected, plus the list of\n * resolved files for context tracking.\n */\nexport async function resolveFileMentions(\n input: string,\n repoRoot: string,\n): Promise<{ prompt: string; files: ResolvedFile[] }> {\n const matches = [...input.matchAll(FILE_MENTION_RE)];\n if (matches.length === 0) return { prompt: input, files: [] };\n return resolveAllFileMentions({ input, repoRoot, matches });\n}\n","/**\n * Shared guards for Node.js system errors.\n *\n * Filesystem and process calls reject with `NodeJS.ErrnoException` — an `Error`\n * carrying a string `code` like `\"ENOENT\"`. `catch` binds these as `unknown`, so\n * every caller that wants to branch on the code first has to narrow the value.\n * These guards are the single place that narrowing lives, replacing the\n * hand-rolled copies that previously sat in each fs-touching module.\n */\n\nimport { Data } from \"effect\";\n\n/**\n * Effect-native tagged error for wrapping Node.js system errors.\n *\n * @param error - The original caught error value.\n * @param code - Optional `errno` code string (e.g. `\"ENOENT\"`).\n */\nexport class NodeError extends Data.TaggedError(\"NodeError\")<{\n readonly error: unknown;\n readonly code?: string;\n}> {}\n\n/**\n * Narrow an unknown caught value to a Node.js system error.\n *\n * Use when you need the typed `.code`/`.errno`/`.path` fields after the check,\n * e.g. `if (isNodeError(error) && error.code === \"ENOENT\") ...`.\n *\n * @param error - The unknown caught value.\n * @returns Whether the value is a NodeJS.ErrnoException.\n */\nexport function isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error;\n}\n\n/**\n * Predicate for \"this caught value is a Node.js error with exactly this code\".\n *\n * The boolean shortcut for the common `ENOENT`-style branch where the narrowed\n * error object itself is not needed afterwards.\n *\n * @param error - The unknown caught value.\n * @param code - The expected error code to match.\n * @returns Whether the value is a Node.js error with the given code.\n */\nexport function hasErrorCode(error: unknown, code: string): boolean {\n return isNodeError(error) && error.code === code;\n}\n","/** OpenAI model documentation root URL. */\nexport const OPENAI_MODELS_URL = \"https://platform.openai.com/docs/models\";\n/** OpenAI GPT-5.2 chat model page URL. */\nexport const OPENAI_GPT_5_2_CHAT_URL =\n \"https://platform.openai.com/docs/models/gpt-5.2-chat-latest\";\n/** OpenAI GPT-5.2 API model page URL. */\nexport const OPENAI_GPT_5_2_URL = \"https://platform.openai.com/docs/models/gpt-5.2\";\n/** OpenAI GPT-4.1 model page URL. */\nexport const OPENAI_GPT_4_1_URL = \"https://platform.openai.com/docs/models/gpt-4.1\";\n/** OpenAI GPT-4o model page URL. */\nexport const OPENAI_GPT_4O_URL = \"https://platform.openai.com/docs/models/gpt-4o\";\n/** Anthropic models overview URL. */\nexport const ANTHROPIC_MODELS_URL = \"https://docs.anthropic.com/en/docs/models-overview\";\n/** Anthropic context window documentation URL. */\nexport const ANTHROPIC_CONTEXT_URL =\n \"https://docs.anthropic.com/en/docs/build-with-claude/context-windows\";\n/** Z.AI models overview URL. */\nexport const ZAI_MODELS_URL = \"https://docs.z.ai/guides/overview/overview\";\n/** Z.AI GLM-5.1 model page URL. */\nexport const ZAI_GLM_5_1_URL = \"https://docs.z.ai/guides/llm/glm-5.1\";\n/** Google Gemini models documentation URL. */\nexport const GEMINI_MODELS_URL = \"https://ai.google.dev/gemini-api/docs/models\";\n","import type { ModelProfile } from \"./modelProfileTypes.ts\";\nimport { ANTHROPIC_CONTEXT_URL, ANTHROPIC_MODELS_URL } from \"./modelUrls.ts\";\n\n/** Anthropic Claude model profiles. */\nexport const ANTHROPIC_MODEL_PROFILES: ModelProfile[] = [\n {\n id: \"claude-4\",\n label: \"Claude 4 family\",\n provider: \"anthropic\",\n aliases: [\"claude\", \"claude sonnet\", \"claude sonnet 4\", \"claude opus 4\", \"claude opus 4.1\"],\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n sourceUrl: ANTHROPIC_MODELS_URL,\n note: \"Anthropic lists 200K for current Claude text models.\",\n },\n {\n id: \"claude-sonnet-4-1m-beta\",\n label: \"Claude Sonnet 4 1M beta\",\n provider: \"anthropic\",\n aliases: [\"claude 1m\", \"sonnet 1m\", \"claude sonnet 4 1m\", \"sonnet[1m]\"],\n contextWindow: 1_000_000,\n maxOutputTokens: 64_000,\n sourceUrl: ANTHROPIC_CONTEXT_URL,\n note: \"Beta requires the context-1m-2025-08-07 header and eligible organization tier.\",\n },\n];\n","import type { ModelProfile } from \"./modelProfileTypes.ts\";\nimport { GEMINI_MODELS_URL } from \"./modelUrls.ts\";\n\n/** Google Gemini model profiles. */\nexport const GOOGLE_MODEL_PROFILES: ModelProfile[] = [\n {\n id: \"gemini-2.5-flash\",\n label: \"Gemini 2.5 Flash\",\n provider: \"google\",\n aliases: [\"gemini\", \"gemini flash\", \"2.5 flash\", \"flash\"],\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n sourceUrl: GEMINI_MODELS_URL,\n note: \"Gemini browser UI label; context window from Gemini API docs.\",\n },\n {\n id: \"gemini-2.5-pro\",\n label: \"Gemini 2.5 Pro\",\n provider: \"google\",\n aliases: [\"gemini pro\", \"2.5 pro\", \"pro\"],\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n sourceUrl: GEMINI_MODELS_URL,\n },\n {\n id: \"gemini-2.5-thinking\",\n label: \"Gemini 2.5 Thinking\",\n provider: \"google\",\n aliases: [\"gemini thinking\", \"2.5 thinking\", \"thinking\"],\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n sourceUrl: GEMINI_MODELS_URL,\n },\n {\n id: \"gemini-3-flash\",\n label: \"Gemini 3 Flash\",\n provider: \"google\",\n aliases: [\"gemini 3\", \"gemini 3 flash\", \"3 flash\"],\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n sourceUrl: GEMINI_MODELS_URL,\n },\n];\n","import type { ModelProfile } from \"./modelProfileTypes.ts\";\nimport { OPENAI_GPT_5_2_CHAT_URL, OPENAI_GPT_5_2_URL, OPENAI_MODELS_URL } from \"./modelUrls.ts\";\n\n/** GPT-5.x ChatGPT browser model profiles. */\nexport const OPENAI_GPT5_MODEL_PROFILES: ModelProfile[] = [\n {\n id: \"gpt-5.5-pro\",\n label: \"GPT-5.5 Pro\",\n provider: \"openai\",\n aliases: [\"gpt-5.5 pro\", \"gpt 5.5 pro\", \"pro\", \"model-switcher-gpt-5-5-pro\"],\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n sourceUrl: OPENAI_MODELS_URL,\n note: \"ChatGPT browser UI label observed from the model picker.\",\n },\n {\n id: \"gpt-5.5-thinking\",\n label: \"GPT-5.5 Thinking\",\n provider: \"openai\",\n aliases: [\n \"gpt-5.5 thinking\",\n \"gpt 5.5 thinking\",\n \"thinking\",\n \"model-switcher-gpt-5-5-thinking\",\n ],\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n sourceUrl: OPENAI_MODELS_URL,\n note: \"ChatGPT browser UI label observed from the model picker.\",\n },\n {\n id: \"gpt-5.3-instant\",\n label: \"GPT-5.3 Instant\",\n provider: \"openai\",\n aliases: [\"gpt-5.3 instant\", \"gpt 5.3 instant\", \"instant\", \"model-switcher-gpt-5-3\"],\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n sourceUrl: OPENAI_MODELS_URL,\n note: \"ChatGPT browser UI label observed from the model picker.\",\n },\n {\n id: \"gpt-5.2-chat-latest\",\n label: \"GPT-5.2 Chat\",\n provider: \"openai\",\n aliases: [\"gpt-5.2\", \"gpt 5.2\", \"gpt-5.2 chat\", \"chatgpt gpt-5.2\", \"gpt-5-2\"],\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n sourceUrl: OPENAI_GPT_5_2_CHAT_URL,\n note: \"ChatGPT browser model alias, not the larger API flagship context.\",\n },\n {\n id: \"gpt-5.2\",\n label: \"GPT-5.2 API\",\n provider: \"openai\",\n aliases: [\"api:gpt-5.2\", \"gpt-5.2 api\", \"openai gpt-5.2\"],\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n sourceUrl: OPENAI_GPT_5_2_URL,\n },\n {\n id: \"gpt-5.1-chat-latest\",\n label: \"GPT-5.1 Chat\",\n provider: \"openai\",\n aliases: [\"gpt-5.1\", \"gpt 5.1\", \"gpt-5.1 chat\", \"chatgpt gpt-5.1\", \"gpt-5-1\"],\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n sourceUrl: \"https://platform.openai.com/docs/models/gpt-5.1-chat-latest\",\n },\n {\n id: \"gpt-5-chat-latest\",\n label: \"GPT-5 Chat\",\n provider: \"openai\",\n aliases: [\"gpt-5\", \"gpt 5\", \"gpt-5 chat\", \"chatgpt gpt-5\", \"gpt-5-0\"],\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n sourceUrl: \"https://platform.openai.com/docs/models/gpt-5-chat-latest\",\n },\n];\n","import type { ModelProfile } from \"./modelProfileTypes.ts\";\nimport { OPENAI_GPT_4O_URL, OPENAI_GPT_4_1_URL } from \"./modelUrls.ts\";\nimport { OPENAI_GPT5_MODEL_PROFILES } from \"./openaiGpt5Profiles.ts\";\n\n/** GPT-4.x and o-series OpenAI model profiles. */\nexport const OPENAI_LEGACY_MODEL_PROFILES: ModelProfile[] = [\n {\n id: \"gpt-4.1\",\n label: \"GPT-4.1 API\",\n provider: \"openai\",\n aliases: [\"api:gpt-4.1\", \"gpt-4.1 api\", \"openai gpt-4.1\"],\n contextWindow: 1_047_576,\n maxOutputTokens: 32_768,\n sourceUrl: OPENAI_GPT_4_1_URL,\n },\n {\n id: \"gpt-4o\",\n label: \"GPT-4o\",\n provider: \"openai\",\n aliases: [\"gpt 4o\", \"4o\", \"chatgpt-4o\", \"chatgpt 4o\"],\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n sourceUrl: OPENAI_GPT_4O_URL,\n },\n {\n id: \"gpt-4o-mini\",\n label: \"GPT-4o Mini\",\n provider: \"openai\",\n aliases: [\"gpt 4o mini\", \"4o mini\", \"gpt-4o-mini\"],\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n sourceUrl: \"https://platform.openai.com/docs/models/gpt-4o-mini\",\n },\n {\n id: \"gpt-4\",\n label: \"GPT-4\",\n provider: \"openai\",\n aliases: [\"gpt 4\"],\n contextWindow: 8_192,\n maxOutputTokens: 8_192,\n sourceUrl: \"https://platform.openai.com/docs/models/gpt-4\",\n },\n {\n id: \"o4-mini\",\n label: \"o4-mini\",\n provider: \"openai\",\n aliases: [\"o4 mini\", \"o4mini\"],\n contextWindow: 200_000,\n maxOutputTokens: 100_000,\n sourceUrl: \"https://platform.openai.com/docs/models/o4-mini\",\n },\n];\n\n/** OpenAI and ChatGPT browser model profiles. */\nexport const OPENAI_MODEL_PROFILES: ModelProfile[] = [\n ...OPENAI_GPT5_MODEL_PROFILES,\n ...OPENAI_LEGACY_MODEL_PROFILES,\n];\n","import type { ModelProfile } from \"./modelProfileTypes.ts\";\nimport { ZAI_GLM_5_1_URL, ZAI_MODELS_URL } from \"./modelUrls.ts\";\n\n/** Z.AI GLM model profiles. */\nexport const ZAI_MODEL_PROFILES: ModelProfile[] = [\n {\n id: \"glm-5.1\",\n label: \"GLM-5.1\",\n provider: \"zai\",\n aliases: [\"z.ai\", \"zai\", \"glm\", \"glm-5.1\", \"glm 5.1\"],\n contextWindow: 200_000,\n maxOutputTokens: 128_000,\n sourceUrl: ZAI_GLM_5_1_URL,\n },\n {\n id: \"glm-5\",\n label: \"GLM-5\",\n provider: \"zai\",\n aliases: [\"glm-5\", \"glm 5\"],\n contextWindow: 200_000,\n sourceUrl: ZAI_MODELS_URL,\n },\n {\n id: \"glm-4.5\",\n label: \"GLM-4.5\",\n provider: \"zai\",\n aliases: [\"glm-4.5\", \"glm 4.5\", \"glm-4.5-air\", \"glm 4.5 air\"],\n contextWindow: 128_000,\n maxOutputTokens: 96_000,\n sourceUrl: \"https://docs.z.ai/guides/llm/glm-4.5\",\n },\n];\n","import { ANTHROPIC_MODEL_PROFILES } from \"./anthropicProfiles.ts\";\nimport { GOOGLE_MODEL_PROFILES } from \"./googleProfiles.ts\";\nimport type { ModelProfile } from \"./modelProfileTypes.ts\";\nimport { OPENAI_MODELS_URL } from \"./modelUrls.ts\";\nimport { OPENAI_MODEL_PROFILES } from \"./openaiProfiles.ts\";\nimport { ZAI_MODEL_PROFILES } from \"./zaiProfiles.ts\";\n\n/** Fallback profile for browser-detected models without a stable id. */\nexport const UNKNOWN_MODEL_PROFILE: ModelProfile = {\n id: \"unknown-chatgpt\",\n label: \"ChatGPT\",\n provider: \"unknown\",\n aliases: [\"chatgpt\", \"auto\"],\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n sourceUrl: OPENAI_MODELS_URL,\n note: \"Fallback for browser-detected models that do not expose a stable model id.\",\n};\n\n/** All known model profiles in lookup order. */\nexport const MODEL_PROFILES: ModelProfile[] = [\n ...OPENAI_MODEL_PROFILES,\n ...ANTHROPIC_MODEL_PROFILES,\n ...ZAI_MODEL_PROFILES,\n ...GOOGLE_MODEL_PROFILES,\n];\n","import type { ModelProfile } from \"./modelProfileTypes.ts\";\nimport { MODEL_PROFILES, UNKNOWN_MODEL_PROFILE } from \"./modelProfiles.ts\";\n\ninterface NormalizeKeyInput {\n /** Raw model name or alias from the UI or config. */\n value: string;\n}\n\n/** Normalize a model name for alias lookup. */\nfunction normalizeModelKey(input: NormalizeKeyInput): string {\n return input.value\n .trim()\n .toLowerCase()\n .replace(/chatgpt/g, \"chatgpt \")\n .replace(/[^a-z0-9.:]+/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\ninterface ModelKeysInput {\n /** Profile whose id, label, and aliases become lookup keys. */\n profile: ModelProfile;\n}\n\n/** Build normalized lookup keys for a profile. */\nfunction modelKeys(input: ModelKeysInput): string[] {\n const keys = [input.profile.id, input.profile.label, ...input.profile.aliases];\n return keys.map((value) => normalizeModelKey({ value }));\n}\n\n/** Resolve a model profile from a browser label or config alias. */\nexport function findModelProfile(modelName: string | undefined): ModelProfile {\n if (!modelName?.trim()) return UNKNOWN_MODEL_PROFILE;\n\n const query = normalizeModelKey({ value: modelName });\n if (modelKeys({ profile: UNKNOWN_MODEL_PROFILE }).includes(query)) {\n return UNKNOWN_MODEL_PROFILE;\n }\n\n for (const profile of MODEL_PROFILES) {\n if (modelKeys({ profile }).includes(query)) return profile;\n }\n\n return { ...UNKNOWN_MODEL_PROFILE, label: modelName.trim() };\n}\n\n/** Return a copy of all registered model profiles. */\nexport function listModelProfiles(): ModelProfile[] {\n return [...MODEL_PROFILES];\n}\n","import type { PermissionMode } from \"./domainSchemas.ts\";\nimport type { ToolResult } from \"./types.ts\";\n\nexport type { PermissionMode } from \"./domainSchemas.ts\";\n\nexport const PERMISSION_MODES = [\"read-only\", \"ask\", \"auto\"] as const;\n\nexport type ToolPermissionKind = \"read\" | \"write\" | \"test\" | \"process\";\nexport type PermissionDecisionStatus = \"allowed\" | \"blocked\" | \"needs-confirmation\";\n\nexport interface ToolPermissionDecision {\n toolName: string;\n mode: PermissionMode;\n kind: ToolPermissionKind;\n allowed: boolean;\n status: PermissionDecisionStatus;\n reason: string;\n message: string;\n}\n\nconst READ_TOOLS = new Set([\"grep_code\", \"read_file\", \"git_diff\"]);\nconst WRITE_TOOLS = new Set([\"apply_patch\"]);\nconst TEST_TOOLS = new Set([\"run_tests\"]);\n\n/**\n * Normalize untrusted config input into a safe runtime permission mode.\n *\n * @param value - The raw config value to normalize.\n * @returns A valid PermissionMode, defaulting to \"read-only\".\n */\nexport function normalizePermissionMode(value: unknown): PermissionMode {\n return typeof value === \"string\" && isPermissionMode(value) ? value : \"read-only\";\n}\n\n/**\n * Type guard for PermissionMode values.\n *\n * @param value - The string to check.\n * @returns Whether the string is a valid PermissionMode.\n */\nexport function isPermissionMode(value: string): value is PermissionMode {\n return (PERMISSION_MODES as readonly string[]).includes(value);\n}\n\n/**\n * Classify an MCP tool into the access level needed to run it.\n *\n * @param toolName - The registered MCP tool name.\n * @returns The permission kind required by this tool.\n */\nexport function toolPermissionKind(toolName: string): ToolPermissionKind {\n if (READ_TOOLS.has(toolName)) return \"read\";\n if (WRITE_TOOLS.has(toolName)) return \"write\";\n if (TEST_TOOLS.has(toolName)) return \"test\";\n return \"process\";\n}\n\n/**\n * Evaluate whether the current permission mode allows a tool call.\n *\n * @param toolName - The registered MCP tool name.\n * @param modeInput - The raw permission mode value (will be normalized).\n * @returns A decision object describing whether the tool is allowed.\n */\nexport function evaluateToolPermission(\n toolName: string,\n modeInput: unknown,\n): ToolPermissionDecision {\n const mode = normalizePermissionMode(modeInput);\n const kind = toolPermissionKind(toolName);\n\n if (kind === \"read\" || mode === \"auto\") {\n return {\n toolName,\n mode,\n kind,\n allowed: true,\n status: \"allowed\",\n reason: \"allowed\",\n message: `Tool ${toolName} is allowed in ${mode} mode.`,\n };\n }\n\n if (mode === \"ask\") {\n return {\n toolName,\n mode,\n kind,\n allowed: false,\n status: \"needs-confirmation\",\n reason: \"interactive-confirmation-unavailable\",\n message: `Tool ${toolName} requires ${kind} access, but permission mode ask cannot continue because interactive confirmation is not implemented yet.`,\n };\n }\n\n return {\n toolName,\n mode,\n kind,\n allowed: false,\n status: \"blocked\",\n reason: \"permission-mode-read-only\",\n message: `Tool ${toolName} requires ${kind} access, but permission mode read-only only allows read tools.`,\n };\n}\n\n/**\n * Convert a denied decision into the ToolResult shape used by MCP handlers.\n *\n * @param decision - The permission decision to convert.\n * @returns A ToolResult if denied, or undefined if allowed.\n */\nexport function permissionDecisionToToolResult(\n decision: ToolPermissionDecision,\n): ToolResult | undefined {\n if (decision.allowed) return undefined;\n return {\n ok: false,\n output: decision.message,\n error: decision.reason,\n };\n}\n","/**\n * Effect Schema definitions for the domain feature.\n *\n * These schemas are the single source of truth for runtime validation of\n * domain types. Pure TypeScript interfaces in `types/` remain for structural\n * typing; these schemas add encode/decode + validation at boundaries.\n */\n\nimport { Schema } from \"effect\";\n\n/**\n * Schema for the permission mode governing MCP tool access.\n */\nexport const PermissionModeSchema = Schema.Literal(\"read-only\", \"ask\", \"auto\");\n\n/**\n * Permission mode type derived from the schema.\n */\nexport type PermissionMode = Schema.Schema.Type<typeof PermissionModeSchema>;\n\n/**\n * Schema for the result shape returned by MCP tool handlers.\n */\nexport const ToolResultSchema = Schema.Struct({\n ok: Schema.Boolean,\n output: Schema.String,\n error: Schema.optional(Schema.String),\n});\n\n/**\n * ToolResult type derived from the schema.\n */\nexport type ToolResult = Schema.Schema.Type<typeof ToolResultSchema>;\n\n/**\n * Schema for the persisted bridge configuration.\n */\nexport const BridgeConfigSchema = Schema.Struct({\n repoPath: Schema.String,\n provider: Schema.optional(Schema.String),\n mcpPort: Schema.Number,\n tunnelUrl: Schema.optional(Schema.String),\n contextLimit: Schema.Number,\n model: Schema.optional(Schema.String),\n permissionMode: Schema.optional(PermissionModeSchema),\n});\n\n/**\n * BridgeConfig type derived from the schema.\n */\nexport type BridgeConfig = Schema.Schema.Type<typeof BridgeConfigSchema>;\n","import { type ChildProcess, spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { readFile, stat } from \"node:fs/promises\";\nimport { createServer } from \"node:http\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { resolve } from \"node:path\";\nimport { DEFAULT_PERMISSION_MODE } from \"@/config\";\nimport type { PermissionMode } from \"@/features/domain\";\nimport { evaluateToolPermission, permissionDecisionToToolResult } from \"@/features/domain\";\nimport type { ToolDef, ToolResult } from \"@/features/domain\";\nimport { loadManifest } from \"@/features/providers\";\nimport { createCheckpoint } from \"@/features/store\";\nimport { appendBridgeLog } from \"@/features/store\";\nimport type { HookDefinition } from \"@/features/user-config\";\nimport { runHooks } from \"@/features/user-config\";\nimport { McpServer as McpProtocolServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { SSEServerTransport } from \"@modelcontextprotocol/sdk/server/sse.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { isInitializeRequest } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Page } from \"playwright\";\nimport { z } from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Lifecycle event emitted when an MCP tool runs. */\nexport interface McpToolAction {\n name: string;\n status: \"started\" | \"completed\" | \"blocked\" | \"failed\";\n data?: Record<string, unknown>;\n}\n\n/** Hooks and callbacks wired into the MCP server. */\nexport interface McpServerOptions {\n getPage?: () => Page | null | undefined;\n getPermissionMode?: () => PermissionMode;\n hooks?: readonly HookDefinition[];\n onToolAction?: (action: McpToolAction) => void | Promise<void>;\n}\n\n/** A running MCP server: its local base URL and a handle to stop it. */\nexport interface McpServerHandle {\n url: string;\n close: () => void;\n}\n\n/** Internal SSE transport pairing. */\ninterface McpConnection {\n server: McpProtocolServer;\n transport: SSEServerTransport;\n}\n\n/** Internal streamable HTTP transport pairing. */\ninterface StreamableMcpConnection {\n server: McpProtocolServer;\n transport: StreamableHTTPServerTransport;\n}\n\n// ---------------------------------------------------------------------------\n// Sandbox\n// ---------------------------------------------------------------------------\n\n/** Ensure a user-supplied path resolves inside the repo root. */\nexport function ensureInsideRepo(path: string, repoRoot: string): string {\n const resolved = resolve(repoRoot, path);\n const normalizedRoot = resolve(repoRoot);\n if (resolved !== normalizedRoot && !resolved.startsWith(`${normalizedRoot}/`)) {\n throw new Error(`Path escapes repo root: ${path}`);\n }\n return resolved;\n}\n\n/** Allowlisted test command prefixes — only these may be executed. */\nconst ALLOWED_TEST_PREFIXES: string[][] = [\n [\"npm\", \"test\"],\n [\"npm\", \"run\", \"test\"],\n [\"pnpm\", \"test\"],\n [\"pnpm\", \"run\", \"test\"],\n [\"yarn\", \"test\"],\n [\"pytest\"],\n [\"python\", \"-m\", \"pytest\"],\n [\"go\", \"test\"],\n [\"cargo\", \"test\"],\n [\"make\", \"test\"],\n];\n\n/** Check whether a parsed command matches an allowed test prefix. */\nexport function isAllowedTestCommand(parts: string[]): boolean {\n return ALLOWED_TEST_PREFIXES.some(\n (prefix) => parts.slice(0, prefix.length).join(\" \") === prefix.join(\" \"),\n );\n}\n\n/** Trim output to a max character limit. */\nexport function trimOutput(text: string, limit = 20_000): string {\n if (text.length <= limit) return text;\n return `${text.slice(0, limit)}\\n\\n[trimmed: output exceeded ${limit} chars]`;\n}\n\n// ---------------------------------------------------------------------------\n// Process\n// ---------------------------------------------------------------------------\n\ninterface ProcessResult {\n stdout: string;\n stderr: string;\n code: number | null;\n}\n\ninterface RunProcessOptions {\n timeoutMs?: number;\n stdin?: string;\n}\n\ninterface SpawnProcessInput {\n command: string;\n args: string[];\n cwd: string;\n stdin?: string;\n timeoutMs: number;\n}\n\n/** Run a subprocess without a shell and capture stdout/stderr. */\nfunction runProcess(\n args: readonly string[],\n cwd: string,\n options: RunProcessOptions = {},\n): Promise<ProcessResult> {\n if (args.length === 0) return Promise.resolve({ stdout: \"\", stderr: \"Empty command.\", code: 1 });\n const [command = \"\", ...rest] = args;\n return spawnProcess({\n command,\n args: rest,\n cwd,\n stdin: options.stdin,\n timeoutMs: options.timeoutMs ?? 30_000,\n });\n}\n\n/** Spawn a subprocess and resolve when it exits or times out. */\nfunction spawnProcess(input: SpawnProcessInput): Promise<ProcessResult> {\n return new Promise((done) => {\n const proc = spawn(input.command, input.args, { cwd: input.cwd });\n attachProcessListeners({ proc, timeoutMs: input.timeoutMs, done });\n writeProcessStdin({ proc, stdin: input.stdin });\n });\n}\n\nfunction attachProcessListeners(input: {\n proc: ChildProcess;\n timeoutMs: number;\n done: (result: ProcessResult) => void;\n}): void {\n const output = { stdout: \"\", stderr: \"\" };\n const timer = setTimeout(() => {\n input.proc.kill();\n }, input.timeoutMs);\n attachProcessOutput({ proc: input.proc, output });\n attachProcessCompletion({ proc: input.proc, timer, output, done: input.done });\n}\n\nfunction attachProcessOutput(input: {\n proc: ChildProcess;\n output: { stdout: string; stderr: string };\n}): void {\n input.proc.stdout?.on(\"data\", (chunk: Buffer) => {\n input.output.stdout += chunk.toString();\n });\n input.proc.stderr?.on(\"data\", (chunk: Buffer) => {\n input.output.stderr += chunk.toString();\n });\n}\n\nfunction attachProcessCompletion(input: {\n proc: ChildProcess;\n timer: NodeJS.Timeout;\n output: { stdout: string; stderr: string };\n done: (result: ProcessResult) => void;\n}): void {\n input.proc.on(\"close\", (code) => {\n clearTimeout(input.timer);\n input.done({ stdout: input.output.stdout, stderr: input.output.stderr, code });\n });\n input.proc.on(\"error\", (err) => {\n clearTimeout(input.timer);\n input.done({ stdout: input.output.stdout, stderr: err.message, code: 1 });\n });\n}\n\nfunction writeProcessStdin(input: { proc: ChildProcess; stdin?: string }): void {\n if (input.stdin === undefined) return;\n input.proc.stdin?.write(input.stdin);\n input.proc.stdin?.end();\n}\n\n// ---------------------------------------------------------------------------\n// Read file\n// ---------------------------------------------------------------------------\n\ninterface ReadFileSliceInput {\n safePath: string;\n path: string;\n startLine: number;\n maxLines: number;\n}\n\nasync function readNumberedSlice(input: ReadFileSliceInput): Promise<{ ok: true; output: string }> {\n const raw = await readFile(input.safePath, \"utf-8\");\n const lines = raw.split(\"\\n\");\n const start = Math.max(input.startLine - 1, 0);\n const end = Math.min(start + input.maxLines, lines.length);\n return {\n ok: true,\n output: trimOutput(buildNumberedSliceOutput({ lines, start, end, path: input.path })),\n };\n}\n\nfunction buildNumberedSliceOutput(input: {\n lines: string[];\n start: number;\n end: number;\n path: string;\n}): string {\n const header = `path: ${input.path}\\nlines: ${input.start + 1}-${input.end} of ${input.lines.length}\\n`;\n return header + formatNumberedLines({ lines: input.lines, start: input.start, end: input.end });\n}\n\nfunction formatNumberedLines(input: { lines: string[]; start: number; end: number }): string {\n let text = \"\";\n for (let index = input.start; index < input.end; index += 1) {\n text += `${index + 1}: ${input.lines[index]}\\n`;\n }\n return text.endsWith(\"\\n\") ? text.slice(0, -1) : text;\n}\n\nasync function readFileTool(\n args: Record<string, unknown>,\n): Promise<{ ok: boolean; output: string }> {\n const input = readFileToolInput(args);\n const invalid = await assertReadableFile({ safePath: input.safePath, path: input.path });\n if (invalid) return invalid;\n return await readNumberedSlice(input);\n}\n\nfunction readFileToolInput(args: Record<string, unknown>): ReadFileSliceInput {\n const path = String(args.path);\n const repoRoot = String(args._repoRoot);\n return {\n path,\n safePath: ensureInsideRepo(path, repoRoot),\n startLine: Number(args.start_line ?? 1),\n maxLines: Number(args.max_lines ?? 200),\n };\n}\n\nasync function assertReadableFile(input: { safePath: string; path: string }): Promise<{\n ok: false;\n output: string;\n} | null> {\n try {\n const fileStat = await stat(input.safePath);\n if (!fileStat.isFile()) return { ok: false, output: `Not a file: ${input.path}` };\n } catch {\n return { ok: false, output: `File not found: ${input.path}` };\n }\n return null;\n}\n\nconst readFileDef: ToolDef = {\n name: \"read_file\",\n description: \"Read a repo file with line numbers. Use after grep_code before proposing edits.\",\n annotations: { title: \"Read file\", readOnlyHint: true, openWorldHint: false },\n parameters: {\n path: z.string().describe(\"Repo-relative file path.\"),\n start_line: z.number().optional().describe(\"1-based line number to start reading.\"),\n max_lines: z.number().optional().describe(\"Maximum number of lines to read.\"),\n },\n handler: readFileTool,\n};\n\n// ---------------------------------------------------------------------------\n// Grep\n// ---------------------------------------------------------------------------\n\ninterface BuildRgArgsInput {\n pattern: string;\n safePath: string;\n glob?: string;\n}\n\nfunction buildRgArgs(input: BuildRgArgsInput): string[] {\n const rgArgs = [\n \"rg\",\n \"--line-number\",\n \"--hidden\",\n \"--glob\",\n \"!.git\",\n \"--glob\",\n \"!node_modules\",\n \"--glob\",\n \"!dist\",\n \"--glob\",\n \"!build\",\n ];\n if (input.glob) rgArgs.push(\"--glob\", input.glob);\n rgArgs.push(input.pattern, input.safePath);\n return rgArgs;\n}\n\nfunction grepResultOutput(result: ProcessResult): { ok: boolean; output: string } {\n if (result.code === 1) return { ok: true, output: \"\" };\n if (result.code !== 0) return { ok: false, output: result.stderr };\n return { ok: true, output: trimOutput(result.stdout) };\n}\n\nasync function grepCode(args: Record<string, unknown>): Promise<{ ok: boolean; output: string }> {\n const input = readGrepInput(args);\n const result = await runProcess(buildRgArgs(input), input.repoRoot, { timeoutMs: 20_000 });\n return grepResultOutput(result);\n}\n\nfunction readGrepInput(args: Record<string, unknown>): BuildRgArgsInput & { repoRoot: string } {\n const repoRoot = String(args._repoRoot);\n return {\n pattern: String(args.pattern),\n safePath: ensureInsideRepo(String(args.path), repoRoot),\n glob: args.glob ? String(args.glob) : undefined,\n repoRoot,\n };\n}\n\nconst grepTool: ToolDef = {\n name: \"grep_code\",\n description:\n \"Search the repository using ripgrep. Locate symbols, imports, routes, tests, configs, and references.\",\n annotations: { title: \"Search repo\", readOnlyHint: true, openWorldHint: false },\n parameters: {\n pattern: z.string().describe(\"The ripgrep search pattern.\"),\n path: z.string().describe(\"Repo-relative path to search.\"),\n glob: z.string().optional().describe(\"Optional ripgrep glob, e.g. '*.ts'.\"),\n },\n handler: grepCode,\n};\n\n// ---------------------------------------------------------------------------\n// Apply patch\n// ---------------------------------------------------------------------------\n\ninterface ApplyPatchInput {\n patch: string;\n repoRoot: string;\n patchPaths: string[];\n}\n\nasync function runGitApply(input: ApplyPatchInput): Promise<{ ok: boolean; output: string }> {\n const check = await runProcess([\"git\", \"apply\", \"--check\", \"-\"], input.repoRoot, {\n stdin: input.patch,\n timeoutMs: 20_000,\n });\n if (check.code !== 0) {\n return {\n ok: false,\n output: `Patch check failed:\\n${trimOutput(check.stderr || check.stdout)}`,\n };\n }\n const applied = await runProcess([\"git\", \"apply\", \"-\"], input.repoRoot, {\n stdin: input.patch,\n timeoutMs: 20_000,\n });\n if (applied.code !== 0) {\n return {\n ok: false,\n output: `Patch apply failed:\\n${trimOutput(applied.stderr || applied.stdout)}`,\n };\n }\n return { ok: true, output: \"Patch applied successfully.\" };\n}\n\nasync function createPatchCheckpoints(input: ApplyPatchInput): Promise<string> {\n if (input.patchPaths.length === 0) return \"\";\n const before = await createCheckpoint({\n repoRoot: input.repoRoot,\n paths: input.patchPaths,\n phase: \"before\",\n label: \"apply_patch\",\n });\n const after = await createCheckpoint({\n repoRoot: input.repoRoot,\n paths: input.patchPaths,\n phase: \"after\",\n label: \"apply_patch\",\n });\n return `\\nCheckpoints:\\n- before: ${before.id}\\n- after: ${after.id}`;\n}\n\nasync function applyPatch(args: Record<string, unknown>): Promise<{ ok: boolean; output: string }> {\n const input = readApplyPatchInput(args);\n ensureInsideRepo(\".\", input.repoRoot);\n const patchPaths = extractPatchPaths(input.patch);\n const applied = await runGitApply({ patch: input.patch, repoRoot: input.repoRoot, patchPaths });\n return applied.ok\n ? {\n ok: true,\n output:\n applied.output +\n (await createPatchCheckpoints({\n patch: input.patch,\n repoRoot: input.repoRoot,\n patchPaths,\n })),\n }\n : applied;\n}\n\nfunction readApplyPatchInput(args: Record<string, unknown>): { patch: string; repoRoot: string } {\n return { patch: String(args.patch), repoRoot: String(args._repoRoot) };\n}\n\n/** Extract changed file paths from a unified git patch. */\nexport function extractPatchPaths(patch: string): string[] {\n const paths = new Set<string>();\n for (const line of patch.split(/\\r?\\n/)) {\n const gitMatch = /^diff --git a\\/(.+?) b\\/(.+)$/.exec(line);\n if (gitMatch && gitMatch[1] !== undefined && gitMatch[2] !== undefined) {\n addPatchPath({ paths, path: gitMatch[1] });\n addPatchPath({ paths, path: gitMatch[2] });\n continue;\n }\n const fileMatch = /^(---|\\+\\+\\+) (?:a|b)\\/(.+)$/.exec(line);\n if (fileMatch && fileMatch[2] !== undefined) addPatchPath({ paths, path: fileMatch[2] });\n }\n return [...paths];\n}\n\nfunction addPatchPath(input: { paths: Set<string>; path: string }): void {\n const trimmed = input.path.trim();\n if (!trimmed || trimmed === \"/dev/null\") return;\n input.paths.add(trimmed);\n}\n\nconst applyPatchTool: ToolDef = {\n name: \"apply_patch\",\n description:\n \"Apply a unified diff patch to the repository. Use only after reading the relevant files.\",\n annotations: {\n title: \"Apply patch\",\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n parameters: { patch: z.string().describe(\"Unified diff patch compatible with git apply.\") },\n handler: applyPatch,\n};\n\n// ---------------------------------------------------------------------------\n// Run tests\n// ---------------------------------------------------------------------------\n\nasync function runTests(args: Record<string, unknown>): Promise<{ ok: boolean; output: string }> {\n const command = String(args.command);\n const repoRoot = String(args._repoRoot);\n const denied = validateTestCommand({ parts: command.trim().split(/\\s+/), command });\n if (denied) return denied;\n return formatTestResult(\n await runProcess(command.trim().split(/\\s+/), repoRoot, { timeoutMs: 120_000 }),\n );\n}\n\nfunction validateTestCommand(input: { parts: string[]; command: string }): {\n ok: false;\n output: string;\n} | null {\n if (input.parts.length === 0) return { ok: false, output: \"Empty command.\" };\n if (!isAllowedTestCommand(input.parts)) {\n return {\n ok: false,\n output: `Command not allowlisted: ${input.command}\\nAllowed: npm test, pnpm test, pytest, go test ./..., cargo test, make test`,\n };\n }\n return null;\n}\n\nfunction formatTestResult(result: ProcessResult): { ok: boolean; output: string } {\n const combined = `${result.stdout}\\n${result.stderr}`;\n return { ok: result.code === 0, output: trimOutput(combined.trim()) };\n}\n\nconst runTestsTool: ToolDef = {\n name: \"run_tests\",\n description: \"Run an allowed project test command (npm test, pytest, go test, etc.).\",\n annotations: {\n title: \"Run tests\",\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n parameters: {\n command: z.string().describe(\"Allowed test command, e.g. 'npm test' or 'pytest'.\"),\n },\n handler: runTests,\n};\n\n// ---------------------------------------------------------------------------\n// Git diff\n// ---------------------------------------------------------------------------\n\nasync function gitDiff(args: Record<string, unknown>): Promise<{ ok: boolean; output: string }> {\n const repoRoot = String(args._repoRoot);\n const [stat, diff] = await Promise.all([\n runProcess([\"git\", \"diff\", \"--stat\"], repoRoot, { timeoutMs: 10_000 }),\n runProcess([\"git\", \"diff\"], repoRoot, { timeoutMs: 20_000 }),\n ]);\n const combined = `--- stat ---\\n${stat.stdout}\\n\\n--- diff ---\\n${diff.stdout}`;\n return { ok: true, output: trimOutput(combined) };\n}\n\nconst gitDiffTool: ToolDef = {\n name: \"git_diff\",\n description: \"Show the current git diff and diff stat for the working tree.\",\n annotations: { title: \"Show git diff\", readOnlyHint: true, openWorldHint: false },\n parameters: {},\n handler: gitDiff,\n};\n\n// ---------------------------------------------------------------------------\n// Attachments\n// ---------------------------------------------------------------------------\n\nconst DOWNLOADER_MODULE = \"../../providers/chatgpt/chatgptPage.ts\";\n\ninterface SingleDownloadResult {\n path: string;\n bytes: number;\n}\n\ninterface DownloadResult {\n id?: string;\n path: string;\n bytes: number;\n error?: string;\n}\n\ninterface AttachmentDownloaderModule {\n downloadAttachment(\n page: Page,\n conversationId: string,\n id: string,\n opts?: { outDir?: string; repoRoot?: string },\n ): Promise<unknown>;\n downloadAll(\n page: Page,\n conversationId: string,\n opts?: { outDir?: string; repoRoot?: string; ids?: string[] },\n ): Promise<unknown>;\n}\n\nfunction jsonResult(value: unknown): ToolResult {\n return { ok: true, output: JSON.stringify(value) };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction optionalString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction normalizeSingleDownloadResult(value: unknown): SingleDownloadResult {\n if (!isRecord(value)) return { path: String(value), bytes: 0 };\n return {\n path: typeof value.path === \"string\" ? value.path : \"\",\n bytes: typeof value.bytes === \"number\" ? value.bytes : 0,\n };\n}\n\nfunction normalizeDownloadResult(value: unknown, fallbackId: string): DownloadResult {\n if (!isRecord(value)) return { id: fallbackId, path: String(value), bytes: 0 };\n return {\n id: typeof value.id === \"string\" ? value.id : fallbackId,\n path: typeof value.path === \"string\" ? value.path : \"\",\n bytes: typeof value.bytes === \"number\" ? value.bytes : 0,\n error: typeof value.error === \"string\" ? value.error : undefined,\n };\n}\n\nfunction normalizeDownloadAll(value: unknown): DownloadResult[] {\n if (!Array.isArray(value)) return [];\n const results: DownloadResult[] = [];\n for (let index = 0; index < value.length; index += 1) {\n results.push(normalizeDownloadResult(value[index], `attachment-${index + 1}`));\n }\n return results;\n}\n\nfunction optionalPage(value: unknown): Page | null {\n if (typeof value !== \"object\" || value === null || typeof (value as Page).url !== \"function\")\n return null;\n return value as Page;\n}\n\nfunction resolveConversationId(args: Record<string, unknown>): string {\n const explicit =\n typeof args.conversationId === \"string\" && args.conversationId.length > 0\n ? args.conversationId\n : undefined;\n if (explicit) return explicit;\n const page = optionalPage(args._page);\n if (!page) throw new Error(\"No active ChatGPT browser page is available.\");\n const match = /\\/c\\/([^/?#]+)/.exec(page.url());\n return match?.[1] ?? \"current\";\n}\n\nfunction resolvePage(args: Record<string, unknown>): Page {\n const page = optionalPage(args._page);\n if (!page) throw new Error(\"No active ChatGPT browser page is available.\");\n return page;\n}\n\nasync function loadDownloader(): Promise<AttachmentDownloaderModule> {\n return (await import(DOWNLOADER_MODULE)) as AttachmentDownloaderModule;\n}\n\n/** MCP tool for listing attachments captured in the active ChatGPT conversation. */\nexport const listAttachmentsTool: ToolDef = {\n name: \"chatgpt_list_attachments\",\n description:\n \"List captured attachments in a ChatGPT conversation, including their assistant/user role.\",\n annotations: { title: \"List ChatGPT attachments\", readOnlyHint: true, openWorldHint: false },\n parameters: {\n conversationId: z.string().optional().describe(\"Optional ChatGPT conversation id.\"),\n },\n handler: async (args) =>\n jsonResult((await loadManifest(resolveConversationId(args))).attachments),\n};\n\n/** MCP tool for downloading one captured ChatGPT attachment. */\nexport const downloadAttachmentTool: ToolDef = {\n name: \"chatgpt_download_attachment\",\n description: \"Download one captured attachment from the active ChatGPT conversation.\",\n annotations: {\n title: \"Download ChatGPT attachment\",\n readOnlyHint: false,\n destructiveHint: false,\n openWorldHint: false,\n },\n parameters: {\n conversationId: z.string().optional().describe(\"Optional ChatGPT conversation id.\"),\n id: z.string().describe(\"Attachment id from chatgpt_list_attachments.\"),\n outDir: z\n .string()\n .optional()\n .describe(\n \"Optional output directory; defaults to the repo-local .bridge/downloads/<conversationId> (git-ignored).\",\n ),\n },\n handler: async (args) => {\n const outDir = optionalString(args.outDir);\n const repoRoot = optionalString(args._repoRoot);\n const raw = await (await loadDownloader()).downloadAttachment(\n resolvePage(args),\n resolveConversationId(args),\n String(args.id),\n { ...(outDir ? { outDir } : {}), ...(repoRoot ? { repoRoot } : {}) },\n );\n return jsonResult(normalizeSingleDownloadResult(raw));\n },\n};\n\n/** MCP tool for downloading all or selected captured ChatGPT attachments. */\nexport const downloadAllAttachmentsTool: ToolDef = {\n name: \"chatgpt_download_all\",\n description:\n \"Download all or selected captured attachments from the active ChatGPT conversation.\",\n annotations: {\n title: \"Download all ChatGPT attachments\",\n readOnlyHint: false,\n destructiveHint: false,\n openWorldHint: false,\n },\n parameters: {\n conversationId: z.string().optional().describe(\"Optional ChatGPT conversation id.\"),\n outDir: z\n .string()\n .optional()\n .describe(\n \"Optional output directory; defaults to the repo-local .bridge/downloads/<conversationId> (git-ignored).\",\n ),\n ids: z.array(z.string()).optional().describe(\"Optional attachment ids to download.\"),\n },\n handler: async (args) => {\n const outDir = optionalString(args.outDir);\n const repoRoot = optionalString(args._repoRoot);\n const ids = Array.isArray(args.ids)\n ? args.ids.filter((id): id is string => typeof id === \"string\")\n : undefined;\n const raw = await (await loadDownloader()).downloadAll(\n resolvePage(args),\n resolveConversationId(args),\n {\n ...(outDir ? { outDir } : {}),\n ...(repoRoot ? { repoRoot } : {}),\n ...(ids ? { ids } : {}),\n },\n );\n return jsonResult(normalizeDownloadAll(raw));\n },\n};\n\n// ---------------------------------------------------------------------------\n// Tool registry\n// ---------------------------------------------------------------------------\n\nconst toolRegistry: Map<string, ToolDef> = new Map();\n\nfor (const tool of [\n grepTool,\n readFileDef,\n applyPatchTool,\n runTestsTool,\n gitDiffTool,\n listAttachmentsTool,\n downloadAttachmentTool,\n downloadAllAttachmentsTool,\n]) {\n toolRegistry.set(tool.name, tool);\n}\n\n/** All available MCP tools, indexed by name. */\nexport { toolRegistry };\n\n// ---------------------------------------------------------------------------\n// Tool call handling\n// ---------------------------------------------------------------------------\n\nfunction toolActionStatus(result: ToolResult, blocked: boolean): McpToolAction[\"status\"] {\n if (blocked) return \"blocked\";\n return result.ok ? \"completed\" : \"failed\";\n}\n\nfunction sanitizeToolArgs(args: Record<string, unknown>): Record<string, unknown> {\n const clean: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(args)) {\n if (key === \"_repoRoot\") continue;\n clean[key] = value;\n }\n return clean;\n}\n\nasync function handleToolCall(input: {\n repoRoot: string;\n options: McpServerOptions;\n name: string;\n tool: { handler: (args: Record<string, unknown>) => Promise<ToolResult> };\n args: Record<string, unknown>;\n}) {\n await runHooks(\"PreToolUse\", input.options.hooks ?? []).catch(() => []);\n const result = await executeToolCall(input);\n await runHooks(\"PostToolUse\", input.options.hooks ?? []).catch(() => []);\n return { content: [{ type: \"text\" as const, text: result.output }], isError: !result.ok };\n}\n\nasync function executeToolCall(input: {\n repoRoot: string;\n options: McpServerOptions;\n name: string;\n tool: { handler: (args: Record<string, unknown>) => Promise<ToolResult> };\n args: Record<string, unknown>;\n}): Promise<ToolResult> {\n await logToolCallStart(input);\n const denied = permissionDecisionToToolResult(\n evaluateToolPermission(\n input.name,\n input.options.getPermissionMode?.() ?? DEFAULT_PERMISSION_MODE,\n ),\n );\n const result = await invokeToolHandler({ ...input, denied: denied ?? undefined });\n await logToolCallEnd({ params: input, result, blocked: denied !== undefined });\n return result;\n}\n\nasync function invokeToolHandler(input: {\n repoRoot: string;\n options: McpServerOptions;\n name: string;\n tool: { handler: (args: Record<string, unknown>) => Promise<ToolResult> };\n args: Record<string, unknown>;\n denied?: ToolResult;\n}): Promise<ToolResult> {\n if (input.denied) return input.denied;\n try {\n const page = input.options.getPage?.();\n return await input.tool.handler({\n ...input.args,\n _repoRoot: input.repoRoot,\n ...(page ? { _page: page } : {}),\n });\n } catch (error) {\n return {\n ok: false,\n output: error instanceof Error ? error.message : String(error),\n error: \"tool-handler-error\",\n };\n }\n}\n\nasync function logToolCallStart(input: {\n repoRoot: string;\n options: McpServerOptions;\n name: string;\n args: Record<string, unknown>;\n}): Promise<void> {\n const clean = sanitizeToolArgs(input.args);\n await appendBridgeLog({\n repoPath: input.repoRoot,\n type: \"mcp_tool_call\",\n data: { name: input.name, args: clean },\n }).catch(() => {});\n await input.options.onToolAction?.({\n name: input.name,\n status: \"started\",\n data: { args: clean },\n });\n}\n\nasync function logToolCallEnd(input: {\n params: { repoRoot: string; options: McpServerOptions; name: string };\n result: ToolResult;\n blocked: boolean;\n}): Promise<void> {\n await appendBridgeLog({\n repoPath: input.params.repoRoot,\n type: \"mcp_tool_result\",\n data: {\n name: input.params.name,\n ok: input.result.ok,\n outputBytes: input.result.output.length,\n error: input.result.error,\n },\n }).catch(() => {});\n const status = toolActionStatus(input.result, input.blocked);\n await input.params.options.onToolAction?.({\n name: input.params.name,\n status,\n data: {\n ok: input.result.ok,\n error: input.result.error,\n outputBytes: input.result.output.length,\n },\n });\n}\n\nfunction createMcpProtocolServer(repoRoot: string, options: McpServerOptions): McpProtocolServer {\n const mcp = new McpProtocolServer({ name: \"ai-browser-bridge\", version: \"0.1.0\" });\n for (const [name, tool] of toolRegistry) {\n mcp.tool(\n name,\n tool.description,\n tool.parameters,\n tool.annotations ?? {},\n async (args: Record<string, unknown>) => {\n return handleToolCall({ repoRoot, options, name, tool, args });\n },\n );\n }\n return mcp;\n}\n\n// ---------------------------------------------------------------------------\n// HTTP helpers\n// ---------------------------------------------------------------------------\n\n/** Whether the pathname is an SSE MCP endpoint. */\nexport function isSseEndpointPath(pathname: string): boolean {\n return pathname === \"/\" || pathname === \"/sse\" || pathname === \"/sse/\";\n}\n\n/** Whether the pathname is a streamable HTTP MCP endpoint. */\nexport function isStreamableHttpEndpointPath(pathname: string): boolean {\n return pathname === \"/mcp\" || pathname === \"/mcp/\";\n}\n\nfunction requestPathname(url: string | undefined): string {\n try {\n return new URL(url ?? \"/\", \"http://localhost\").pathname;\n } catch {\n return \"/\";\n }\n}\n\nfunction requestHeader(value: string | string[] | undefined): string | undefined {\n if (Array.isArray(value)) return value[0];\n return value;\n}\n\nasync function readJsonBody(req: IncomingMessage): Promise<unknown> {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n const raw = Buffer.concat(chunks).toString(\"utf-8\");\n return raw ? JSON.parse(raw) : undefined;\n}\n\nfunction writeJsonRpcError(res: ServerResponse, status: number, message: string): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" }).end(\n JSON.stringify({\n jsonrpc: \"2.0\",\n error: { code: -32000, message },\n id: null,\n }),\n );\n}\n\nfunction writeSseProxyFlushPadding(res: ServerResponse): void {\n if (res.writableEnded) return;\n res.write(`: ${\" \".repeat(2048)}\\n\\n`);\n}\n\n// ---------------------------------------------------------------------------\n// McpServer\n// ---------------------------------------------------------------------------\n\n/** MCP HTTP server with SSE and streamable HTTP transports and sandboxed repo tools. */\nexport class McpServer {\n private readonly repoRoot: string;\n private readonly options: McpServerOptions;\n private httpServer: ReturnType<typeof createServer> | null = null;\n private readonly connections = new Map<string, McpConnection>();\n private readonly streamableConnections = new Map<string, StreamableMcpConnection>();\n\n /** Create an MCP server bound to a repo root and optional hooks/callbacks. */\n constructor(repoRoot: string, options: McpServerOptions = {}) {\n this.repoRoot = repoRoot;\n this.options = options;\n }\n\n /** Start listening on the given port and return the local base URL. */\n async start(port: number): Promise<string> {\n this.httpServer = createServer((req, res) => {\n void this.handleRequest(req, res);\n });\n await this.listenOnPort(port);\n return `http://localhost:${port}`;\n }\n\n /** Close all active connections and shut down the HTTP server. */\n stop(): void {\n this.closeAllConnections(this.connections);\n this.closeAllConnections(this.streamableConnections);\n this.httpServer?.close();\n this.httpServer = null;\n }\n\n /** Route an HTTP request to streamable HTTP, SSE, or POST /messages handlers. */\n async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const pathname = requestPathname(req.url);\n if (isStreamableHttpEndpointPath(pathname)) {\n await this.handleStreamableHttpRequest(req, res);\n return;\n }\n if (isSseEndpointPath(pathname)) {\n await this.handleSseRequest(req, res);\n return;\n }\n if (pathname === \"/messages\" && req.method === \"POST\") {\n await this.handleSsePostMessage(req, res);\n return;\n }\n res.writeHead(404).end(\"Not found\");\n }\n\n /** Return all registered MCP tool definitions. */\n listTools(): ToolDef[] {\n return [...toolRegistry.values()];\n }\n\n /** Bind the HTTP server to a port, rejecting on listen errors. */\n private async listenOnPort(port: number): Promise<void> {\n const server = this.httpServer;\n if (!server) throw new Error(\"HTTP server not initialized\");\n const listenError = await new Promise<Error | undefined>((done) => {\n const onError = (err: Error) => done(err);\n server.once(\"error\", onError);\n server.listen(port, () => {\n server.off(\"error\", onError);\n done(undefined);\n });\n });\n if (listenError) throw listenError;\n }\n\n /** Close every MCP protocol server in a connection map. */\n private closeAllConnections(\n connections: Map<string, McpConnection | StreamableMcpConnection>,\n ): void {\n for (const connection of connections.values()) connection.server.close().catch(() => {});\n connections.clear();\n }\n\n /** Accept a new SSE MCP session and connect the protocol server. */\n private async handleSseRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const transport = new SSEServerTransport(\"/messages\", res);\n const mcp = createMcpProtocolServer(this.repoRoot, this.options);\n this.connections.set(transport.sessionId, { server: mcp, transport });\n transport.onclose = () => this.connections.delete(transport.sessionId);\n try {\n await mcp.connect(transport);\n writeSseProxyFlushPadding(res);\n } catch (error) {\n this.connections.delete(transport.sessionId);\n if (!res.headersSent) {\n res.writeHead(500).end(error instanceof Error ? error.message : String(error));\n }\n }\n }\n\n /** Forward a POST /messages request to the matching SSE session transport. */\n private async handleSsePostMessage(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const sessionId = new URL(req.url ?? \"/\", \"http://localhost\").searchParams.get(\"sessionId\");\n const connection = sessionId ? this.connections.get(sessionId) : undefined;\n if (connection) {\n await connection.transport.handlePostMessage(req, res);\n return;\n }\n res.writeHead(503).end(\"No active SSE connection\");\n }\n\n /** Route a streamable HTTP MCP request to an existing or new session. */\n private async handleStreamableHttpRequest(\n req: IncomingMessage,\n res: ServerResponse,\n ): Promise<void> {\n const sessionId = requestHeader(req.headers[\"mcp-session-id\"]);\n let connection = sessionId ? this.streamableConnections.get(sessionId) : undefined;\n let parsedBody: unknown;\n if (!connection) {\n const created = await this.createStreamableConnection(req, res);\n if (!created) return;\n connection = created.connection;\n parsedBody = created.parsedBody;\n }\n try {\n await connection.transport.handleRequest(req, res, parsedBody);\n } catch (error) {\n if (!res.headersSent) {\n writeJsonRpcError(\n res,\n 500,\n error instanceof Error ? error.message : \"Internal server error\",\n );\n }\n }\n }\n\n /** Create a new streamable HTTP session when no session id is provided. */\n private async createStreamableConnection(\n req: IncomingMessage,\n res: ServerResponse,\n ): Promise<{ connection: StreamableMcpConnection; parsedBody: unknown } | null> {\n const sessionId = requestHeader(req.headers[\"mcp-session-id\"]);\n if (sessionId) {\n writeJsonRpcError(res, 404, \"Session not found\");\n return null;\n }\n if (req.method !== \"POST\") {\n writeJsonRpcError(res, 400, \"Bad Request: No valid session ID provided\");\n return null;\n }\n const parsedBody = await readJsonBody(req);\n if (!isInitializeRequest(parsedBody)) {\n writeJsonRpcError(res, 400, \"Bad Request: No valid session ID provided\");\n return null;\n }\n const connection = await this.openStreamableConnection();\n return { connection, parsedBody };\n }\n\n /** Open a streamable HTTP transport and connect the MCP protocol server. */\n private async openStreamableConnection(): Promise<StreamableMcpConnection> {\n let createdConnection: StreamableMcpConnection | null = null;\n const transport = new StreamableHTTPServerTransport({\n enableJsonResponse: true,\n sessionIdGenerator: () => randomUUID(),\n onsessioninitialized: (newSessionId) => {\n if (createdConnection) this.streamableConnections.set(newSessionId, createdConnection);\n },\n });\n createdConnection = { server: createMcpProtocolServer(this.repoRoot, this.options), transport };\n transport.onclose = () => {\n const closedSessionId = transport.sessionId;\n if (closedSessionId) this.streamableConnections.delete(closedSessionId);\n };\n await createdConnection.server.connect(transport);\n return createdConnection;\n }\n}\n","import { readFile, readdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { basename, join, resolve } from \"node:path\";\nimport { hasErrorCode, isNodeError } from \"@/features/domain\";\nimport { BRIDGE_DIR_NAME, HOOKS_FILE, homeHooksPath } from \"@/features/store\";\n\n// ---------------------------------------------------------------------------\n// Hook types\n// ---------------------------------------------------------------------------\n\n/** Supported hook lifecycle event names. */\nexport const HOOK_LIFECYCLE_EVENTS = [\n \"SessionStart\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"Stop\",\n \"SessionEnd\",\n] as const;\n\n/** Hook lifecycle event name. */\nexport type HookLifecycleEvent = (typeof HOOK_LIFECYCLE_EVENTS)[number];\n\n/** Shell command invoked by a hook entry. */\nexport type HookCommand = string | readonly string[];\n\n/** Validated hook definition from hooks.json. */\nexport interface HookDefinition {\n /** Source file path or inline label. */\n source: string;\n /** Lifecycle event that triggers the hook. */\n event: HookLifecycleEvent;\n /** Command to run when execution is enabled. */\n command: HookCommand;\n /** Optional display name. */\n name?: string;\n /** Whether the hook is active. */\n enabled: boolean;\n}\n\n/** Result of parsing a hooks.json payload. */\nexport interface ParseHooksResult {\n /** Valid hook definitions discovered in the payload. */\n hooks: HookDefinition[];\n /** Validation errors collected during parsing. */\n errors: string[];\n}\n\n/** Options for loading hook configs from disk. */\nexport interface LoadHooksOptions {\n /** Repo root whose `.bridge/hooks.json` is loaded first. */\n repoRoot: string;\n /** Optional home directory override for tests. */\n homeDir?: string;\n}\n\n/** Loaded hook configs from all search paths. */\nexport interface LoadedHooksConfig extends ParseHooksResult {\n /** Hook config paths that were searched. */\n paths: string[];\n}\n\n/** Status for a hook run attempt. */\nexport type HookRunStatus = \"skipped\" | \"disabled\";\n\n/** Result of attempting to run one hook. */\nexport interface HookRunResult {\n /** Lifecycle event that was evaluated. */\n event: HookLifecycleEvent;\n /** Hook command that would have run. */\n command: HookCommand;\n /** Whether the hook was skipped or disabled. */\n status: HookRunStatus;\n /** Reason command execution did not occur. */\n reason: \"hook-command-execution-disabled\" | \"hook-disabled\";\n}\n\n/** Raw hook fields extracted from JSON. */\ninterface RawHookFields {\n /** Lifecycle event name. */\n event?: unknown;\n /** Command string or argv array. */\n command?: unknown;\n /** Optional hook display name. */\n name?: unknown;\n /** Optional enabled flag. */\n enabled?: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Custom command types\n// ---------------------------------------------------------------------------\n\n/** Source directory for a custom command definition. */\nexport type CustomCommandSource = \"project\" | \"user\";\n\n/** Optional YAML frontmatter metadata for a custom command. */\nexport interface CustomCommandMetadata {\n /** Short description shown in help output. */\n description?: string;\n /** Preferred model override for the command. */\n model?: string;\n /** Tool names allowed when running the command. */\n allowedTools?: string[];\n}\n\n/** Loaded custom command ready for rendering. */\nexport interface CustomCommand {\n /** Command name derived from the markdown filename. */\n name: string;\n /** Absolute path to the markdown file. */\n filePath: string;\n /** Whether the command came from project or user config. */\n source: CustomCommandSource;\n /** Optional description from frontmatter. */\n description?: string;\n /** Optional model override from frontmatter. */\n model?: string;\n /** Allowed tool names from frontmatter. */\n allowedTools: string[];\n /** Prompt template body after frontmatter. */\n promptTemplate: string;\n}\n\n/** Options for discovering custom commands on disk. */\nexport interface LoadCustomCommandsOptions {\n /** Repo root whose `.bridge/commands` directory is searched. */\n repoRoot: string;\n /** Optional home directory override. */\n homeDir?: string;\n}\n\n/** Parsed markdown command file contents. */\nexport interface ParsedCommandFile {\n /** Frontmatter metadata when present. */\n metadata: CustomCommandMetadata;\n /** Prompt template body. */\n body: string;\n}\n\n/** Directory entry used while scanning command sources. */\ninterface CommandDir {\n /** Whether commands come from project or user config. */\n source: CustomCommandSource;\n /** Absolute directory path to scan. */\n dir: string;\n}\n\n// ---------------------------------------------------------------------------\n// Project instruction types\n// ---------------------------------------------------------------------------\n\n/** Repo-root instruction file name. */\nexport interface ProjectInstructionFile {\n fileName: \"AGENTS.md\" | \"CLAUDE.md\";\n content: string;\n}\n\n/** Loaded project instruction files and rendered prompt text. */\nexport interface ProjectInstructions {\n files: ProjectInstructionFile[];\n promptText: string;\n}\n\nconst PROJECT_INSTRUCTION_FILES: Array<ProjectInstructionFile[\"fileName\"]> = [\n \"AGENTS.md\",\n \"CLAUDE.md\",\n];\n\n// ---------------------------------------------------------------------------\n// UserConfig\n// ---------------------------------------------------------------------------\n\n/** Reads user and project config from `~/.ai-browser-bridge/` and `.bridge/`. */\nexport class UserConfig {\n /** Load local and user hook configs, collecting validation errors. */\n async loadHooks(options: LoadHooksOptions): Promise<LoadedHooksConfig> {\n const paths = hookConfigPaths(options.repoRoot, options.homeDir);\n const hooks: HookDefinition[] = [];\n const errors: string[] = [];\n for (const path of paths) {\n const loaded = await this.readHookFile(path);\n if (!loaded) continue;\n hooks.push(...loaded.hooks);\n errors.push(...loaded.errors);\n }\n return { paths, hooks, errors };\n }\n\n /** Discover markdown-backed custom commands from user and project command dirs. */\n async loadCustomCommands(options: LoadCustomCommandsOptions): Promise<CustomCommand[]> {\n const dirs = this.commandDirs(options);\n const commands: CustomCommand[] = [];\n for (const entry of dirs) {\n commands.push(...(await this.loadCommandsFromDir(entry)));\n }\n return commands.sort(compareCustomCommands);\n }\n\n /** Load repo-root project instructions for /task prompt augmentation. */\n async loadProjectInstructions(repoRoot: string): Promise<ProjectInstructions> {\n const files: ProjectInstructionFile[] = [];\n for (const fileName of PROJECT_INSTRUCTION_FILES) {\n const content = await this.readOptionalFile(join(repoRoot, fileName));\n if (content !== null) {\n files.push({ fileName, content: content.trim() });\n }\n }\n return {\n files,\n promptText: renderProjectInstructions(files),\n };\n }\n\n /** Read and parse one hooks.json file from disk. */\n private async readHookFile(path: string): Promise<ParseHooksResult | null> {\n let raw: string;\n try {\n raw = await readFile(path, \"utf-8\");\n } catch (error) {\n if (hasErrorCode(error, \"ENOENT\")) return null;\n throw error;\n }\n try {\n return parseHooksConfig({ raw: JSON.parse(raw), source: path });\n } catch (error) {\n return { hooks: [], errors: [`${path}: invalid JSON (${errorMessage(error)})`] };\n }\n }\n\n /** Return command directory entries in scan order. */\n private commandDirs(options: LoadCustomCommandsOptions): CommandDir[] {\n const home = options.homeDir ?? process.env.HOME ?? \"\";\n return [\n { source: \"user\", dir: resolve(home, BRIDGE_DIR_NAME, \"commands\") },\n { source: \"project\", dir: resolve(options.repoRoot, \".bridge\", \"commands\") },\n ];\n }\n\n /** Load all markdown commands from one directory. */\n private async loadCommandsFromDir(entry: CommandDir): Promise<CustomCommand[]> {\n const commands: CustomCommand[] = [];\n for (const fileName of await this.readMarkdownFiles(entry.dir)) {\n commands.push(await this.loadCommandFile({ entry, fileName }));\n }\n return commands;\n }\n\n /** Load one custom command markdown file. */\n private async loadCommandFile(input: {\n entry: CommandDir;\n fileName: string;\n }): Promise<CustomCommand> {\n const filePath = join(input.entry.dir, input.fileName);\n const parsed = parseCustomCommandFile(await readFile(filePath, \"utf-8\"));\n return {\n name: basename(input.fileName, \".md\"),\n filePath,\n source: input.entry.source,\n description: parsed.metadata.description,\n model: parsed.metadata.model,\n allowedTools: parsed.metadata.allowedTools ?? [],\n promptTemplate: parsed.body,\n };\n }\n\n /** List markdown files in a command directory. */\n private async readMarkdownFiles(dir: string): Promise<string[]> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries\n .filter((entry) => entry.isFile() && entry.name.endsWith(\".md\"))\n .map((entry) => entry.name)\n .sort(compareStrings);\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") return [];\n throw error;\n }\n }\n\n /** Read a file when present, returning null on ENOENT. */\n private async readOptionalFile(path: string): Promise<string | null> {\n try {\n return await readFile(path, \"utf-8\");\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") return null;\n throw error;\n }\n }\n}\n\n/** Return hook config search paths in deterministic load order. */\nexport function hookConfigPaths(\n input: { repoRoot: string; homeDir?: string } | string,\n homeDir = homedir(),\n): string[] {\n const repoRoot = typeof input === \"string\" ? input : input.repoRoot;\n const home = typeof input === \"string\" ? homeDir : (input.homeDir ?? homedir());\n return [join(repoRoot, \".bridge\", HOOKS_FILE), homeHooksPath(home)];\n}\n\n/** Whether a string is a supported hook lifecycle event. */\nexport function isHookLifecycleEvent(value: string): value is HookLifecycleEvent {\n return (HOOK_LIFECYCLE_EVENTS as readonly string[]).includes(value);\n}\n\n/** Whether a value is a supported hook command shape. */\nfunction isHookCommand(value: unknown): value is string | readonly string[] {\n return (\n typeof value === \"string\" ||\n (Array.isArray(value) && value.every((part) => typeof part === \"string\"))\n );\n}\n\n/** Whether a value is a plain object record. */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Convert unknown JSON into a record, defaulting to empty. */\nfunction asRecord(raw: unknown): Record<string, unknown> {\n return isRecord(raw) ? raw : {};\n}\n\n/** Read one property from a record-like JSON value. */\nfunction readObjectProperty(raw: unknown, property: string): unknown {\n if (!isRecord(raw)) return undefined;\n return raw[property];\n}\n\n/** Format an unknown thrown value as a message string. */\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** Compare custom commands for stable sorting by name then source. */\nfunction compareCustomCommands(left: CustomCommand, right: CustomCommand): number {\n const byName = left.name.localeCompare(right.name);\n return byName !== 0 ? byName : left.source.localeCompare(right.source);\n}\n\n/** Locale-aware string comparator for sorting file names. */\nfunction compareStrings(left: string, right: string): number {\n return left.localeCompare(right);\n}\n\n// ---------------------------------------------------------------------------\n// Hook parsing (module-level)\n// ---------------------------------------------------------------------------\n\n/** Parse and validate a hooks.json payload without executing anything. */\nexport function parseHooksConfig(\n input: { raw: unknown; source?: string } | unknown,\n source = \"inline\",\n): ParseHooksResult {\n const payload =\n typeof input === \"object\" && input !== null && \"raw\" in input\n ? (input as { raw: unknown; source?: string })\n : { raw: input, source };\n const hooksValue = readObjectProperty(payload.raw, \"hooks\");\n if (Array.isArray(hooksValue))\n return parseHookArray({ hooksValue, source: payload.source ?? source });\n if (isRecord(hooksValue))\n return parseHookObject({ hooksValue, source: payload.source ?? source });\n return { hooks: [], errors: [`${payload.source ?? source}: hooks must be an array or object`] };\n}\n\n/** Parse a hooks array payload. */\nfunction parseHookArray(input: { hooksValue: unknown[]; source: string }): ParseHooksResult {\n const hooks: HookDefinition[] = [];\n const errors: string[] = [];\n for (let index = 0; index < input.hooksValue.length; index += 1) {\n const parsed = parseHookEntry({\n raw: input.hooksValue[index],\n source: input.source,\n location: String(index),\n });\n if (parsed.hook) hooks.push(parsed.hook);\n errors.push(...parsed.errors);\n }\n return { hooks, errors };\n}\n\n/** Parse a hooks object keyed by lifecycle event. */\nfunction parseHookObject(input: {\n hooksValue: Record<string, unknown>;\n source: string;\n}): ParseHooksResult {\n const hooks: HookDefinition[] = [];\n const errors: string[] = [];\n for (const [eventName, value] of Object.entries(input.hooksValue)) {\n const eventErrors = parseHookEventHooks({ eventName, value, source: input.source, hooks });\n errors.push(...eventErrors);\n }\n return { hooks, errors };\n}\n\n/** Parse hooks for one lifecycle event key. */\nfunction parseHookEventHooks(input: {\n eventName: string;\n value: unknown;\n source: string;\n hooks: HookDefinition[];\n}): string[] {\n if (!isHookLifecycleEvent(input.eventName)) {\n return [`${input.source}: unsupported hook event ${input.eventName}`];\n }\n if (!Array.isArray(input.value)) {\n return [`${input.source}: ${input.eventName} must be an array`];\n }\n const errors: string[] = [];\n for (let index = 0; index < input.value.length; index += 1) {\n const parsed = parseHookEntry({\n raw: { ...asRecord(input.value[index]), event: input.eventName },\n source: input.source,\n location: `${input.eventName}[${index}]`,\n });\n if (parsed.hook) input.hooks.push(parsed.hook);\n errors.push(...parsed.errors);\n }\n return errors;\n}\n\n/** Parse one hook entry from raw JSON. */\nfunction parseHookEntry(input: { raw: unknown; source: string; location: string }): {\n hook?: HookDefinition;\n errors: string[];\n} {\n const fields = readHookFields(input.raw);\n const errors = validateHookFields({ fields, source: input.source, location: input.location });\n if (\n errors.length > 0 ||\n typeof fields.event !== \"string\" ||\n !isHookLifecycleEvent(fields.event)\n ) {\n return { errors };\n }\n if (!isHookCommand(fields.command)) return { errors };\n return {\n hook: {\n source: input.source,\n event: fields.event,\n command: fields.command,\n name: typeof fields.name === \"string\" ? fields.name : undefined,\n enabled: fields.enabled !== false,\n },\n errors,\n };\n}\n\n/** Extract raw hook fields from a JSON value. */\nfunction readHookFields(raw: unknown): RawHookFields {\n if (!isRecord(raw)) return {};\n return { event: raw.event, command: raw.command, name: raw.name, enabled: raw.enabled };\n}\n\n/** Validate raw hook fields and return error messages. */\nfunction validateHookFields(input: {\n fields: RawHookFields;\n source: string;\n location: string;\n}): string[] {\n const errors: string[] = [];\n if (typeof input.fields.event !== \"string\" || !isHookLifecycleEvent(input.fields.event)) {\n errors.push(`${input.source}: ${input.location}.event must be a supported lifecycle event`);\n }\n if (!isHookCommand(input.fields.command)) {\n errors.push(`${input.source}: ${input.location}.command must be a string or string array`);\n }\n if (input.fields.name !== undefined && typeof input.fields.name !== \"string\") {\n errors.push(`${input.source}: ${input.location}.name must be a string`);\n }\n if (input.fields.enabled !== undefined && typeof input.fields.enabled !== \"boolean\") {\n errors.push(`${input.source}: ${input.location}.enabled must be a boolean`);\n }\n return errors;\n}\n\n/** Run hooks for an event without executing shell commands yet. */\nexport async function runHooks(\n input: { event: HookLifecycleEvent; hooks: readonly HookDefinition[] } | HookLifecycleEvent,\n hooks?: readonly HookDefinition[],\n): Promise<HookRunResult[]> {\n const event = typeof input === \"string\" ? input : input.event;\n const definitions = typeof input === \"string\" ? (hooks ?? []) : input.hooks;\n return definitions\n .filter((hook) => hook.event === event)\n .map((hook) => mapHookRun({ event, hook }));\n}\n\n/** Map one hook definition to a run result. */\nfunction mapHookRun(input: { event: HookLifecycleEvent; hook: HookDefinition }): HookRunResult {\n if (!input.hook.enabled) {\n return {\n event: input.event,\n command: input.hook.command,\n status: \"disabled\",\n reason: \"hook-disabled\",\n };\n }\n return {\n event: input.event,\n command: input.hook.command,\n status: \"skipped\",\n reason: \"hook-command-execution-disabled\",\n };\n}\n\n// ---------------------------------------------------------------------------\n// Custom command parsing (module-level)\n// ---------------------------------------------------------------------------\n\n/** Parse optional YAML-like frontmatter from a custom command markdown file. */\nexport function parseCustomCommandFile(markdown: string): ParsedCommandFile {\n const normalized = markdown.replace(/\\r\\n/g, \"\\n\");\n if (normalized.split(\"\\n\")[0]?.trim() !== \"---\") {\n return { metadata: {}, body: trimOuterBlankLines(normalized) };\n }\n return parseFrontmatterMarkdown(normalized);\n}\n\n/** Render a command template with $ARGUMENTS and positional placeholders. */\nexport function renderCustomCommandPrompt(\n command: CustomCommand,\n args: string | readonly string[] = \"\",\n): string {\n const parsedArgs = typeof args === \"string\" ? splitCommandArguments(args) : [...args];\n const argumentsText = typeof args === \"string\" ? args.trim() : parsedArgs.join(\" \");\n return command.promptTemplate.replace(/\\$(ARGUMENTS|\\d+)/g, (match) =>\n renderTemplateReplacement({ match, argumentsText, parsedArgs }),\n );\n}\n\n/** Parse markdown with YAML-like frontmatter into metadata and body. */\nfunction parseFrontmatterMarkdown(normalized: string): ParsedCommandFile {\n const lines = normalized.split(\"\\n\");\n const endIndex = findFrontmatterEnd(lines);\n if (endIndex === -1) return { metadata: {}, body: trimOuterBlankLines(normalized) };\n return {\n metadata: parseFrontmatter(lines.slice(1, endIndex)),\n body: trimOuterBlankLines(lines.slice(endIndex + 1).join(\"\\n\")),\n };\n}\n\n/** Find the closing frontmatter delimiter line index. */\nfunction findFrontmatterEnd(lines: string[]): number {\n for (let index = 1; index < lines.length; index += 1) {\n if (lines[index]?.trim() === \"---\") return index;\n }\n return -1;\n}\n\n/** Parse optional YAML-like frontmatter lines into metadata. */\nfunction parseFrontmatter(lines: string[]): CustomCommandMetadata {\n const metadata: CustomCommandMetadata = {};\n for (let index = 0; index < lines.length; index += 1) {\n index = applyFrontmatterLine({ metadata, lines, index }) ?? index;\n }\n return metadata;\n}\n\n/** Apply one frontmatter line to metadata when it matches a key. */\nfunction applyFrontmatterLine(input: {\n metadata: CustomCommandMetadata;\n lines: string[];\n index: number;\n}): number | undefined {\n const keyValue = /^([A-Za-z][A-Za-z0-9_-]*):\\s*(.*)$/.exec(input.lines[input.index] ?? \"\");\n if (!keyValue) return undefined;\n return applyFrontmatterKey({\n metadata: input.metadata,\n lines: input.lines,\n index: input.index,\n key: keyValue[1] ?? \"\",\n value: (keyValue[2] ?? \"\").trim(),\n });\n}\n\n/** Apply one parsed frontmatter key to metadata. */\nfunction applyFrontmatterKey(input: {\n metadata: CustomCommandMetadata;\n lines: string[];\n index: number;\n key: string;\n value: string;\n}): number | undefined {\n if (input.key === \"description\") input.metadata.description = stripYamlQuotes(input.value);\n if (input.key === \"model\") input.metadata.model = stripYamlQuotes(input.value);\n if (input.key === \"allowedTools\")\n return parseAllowedTools({\n metadata: input.metadata,\n lines: input.lines,\n index: input.index,\n value: input.value,\n });\n return input.index;\n}\n\n/** Parse allowedTools from inline or list frontmatter. */\nfunction parseAllowedTools(input: {\n metadata: CustomCommandMetadata;\n lines: string[];\n index: number;\n value: string;\n}): number {\n if (input.value) {\n input.metadata.allowedTools = parseInlineList(input.value);\n return input.index;\n }\n return parseAllowedToolsList(input);\n}\n\n/** Parse a YAML list block for allowedTools. */\nfunction parseAllowedToolsList(input: {\n metadata: CustomCommandMetadata;\n lines: string[];\n index: number;\n}): number {\n const list: string[] = [];\n let index = input.index;\n while (index + 1 < input.lines.length) {\n const listItem = /^\\s*-\\s*(.+)$/.exec(input.lines[index + 1] ?? \"\");\n if (!listItem) break;\n list.push(stripYamlQuotes((listItem[1] ?? \"\").trim()));\n index += 1;\n }\n input.metadata.allowedTools = list;\n return index;\n}\n\n/** Split a slash-command argument string respecting quotes. */\nfunction splitCommandArguments(input: string): string[] {\n const state = { args: [] as string[], current: \"\", quote: null as \"'\" | '\"' | null };\n for (const char of input.trim()) {\n const next = consumeArgumentChar({ char, state });\n state.current = next.current;\n state.quote = next.quote;\n }\n if (state.current) state.args.push(state.current);\n return state.args;\n}\n\n/** Consume one character while splitting command arguments. */\nfunction consumeArgumentChar(input: {\n char: string;\n state: { args: string[]; current: string; quote: \"'\" | '\"' | null };\n}): { current: string; quote: \"'\" | '\"' | null } {\n const { char, state } = input;\n if ((char === \"'\" || char === '\"') && state.quote === null) {\n return { current: state.current, quote: char };\n }\n if (char === state.quote) return { current: state.current, quote: null };\n if (/\\s/.test(char) && state.quote === null) {\n if (state.current) state.args.push(state.current);\n return { current: \"\", quote: state.quote };\n }\n return { current: state.current + char, quote: state.quote };\n}\n\n/** Replace one $ARGUMENTS or positional placeholder in a command template. */\nfunction renderTemplateReplacement(input: {\n match: string;\n argumentsText: string;\n parsedArgs: string[];\n}): string {\n if (input.match === \"$ARGUMENTS\") return input.argumentsText;\n const index = Number.parseInt(input.match.slice(1), 10) - 1;\n return input.parsedArgs[index] ?? \"\";\n}\n\n/** Strip surrounding YAML quotes from a scalar value. */\nfunction stripYamlQuotes(value: string): string {\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n return value.slice(1, -1);\n }\n return value;\n}\n\n/** Parse a comma-separated or bracketed inline YAML list. */\nfunction parseInlineList(value: string): string[] {\n const withoutBrackets = value.startsWith(\"[\") && value.endsWith(\"]\") ? value.slice(1, -1) : value;\n return withoutBrackets\n .split(\",\")\n .map((item) => stripYamlQuotes(item.trim()))\n .filter(Boolean);\n}\n\n/** Trim leading and trailing blank lines from markdown bodies. */\nfunction trimOuterBlankLines(value: string): string {\n return value.replace(/^\\n+/, \"\").replace(/\\n+$/, \"\");\n}\n\n// ---------------------------------------------------------------------------\n// Project instructions (module-level)\n// ---------------------------------------------------------------------------\n\n/** Render instruction files with stable headings so multiple files stay distinct. */\nexport function renderProjectInstructions(files: readonly ProjectInstructionFile[]): string {\n return files\n .filter((file) => file.content.trim())\n .map((file) => `## Project Instructions: ${file.fileName}\\n${file.content.trim()}`)\n .join(\"\\n\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Convenience wrappers (backward-compatible function exports)\n// ---------------------------------------------------------------------------\n\nconst defaultUserConfig = new UserConfig();\n\n/** Load local and user hook configs via the default {@link UserConfig} instance. */\nexport async function loadHooksConfig(options: LoadHooksOptions): Promise<LoadedHooksConfig> {\n return defaultUserConfig.loadHooks(options);\n}\n\n/** Discover custom commands via the default {@link UserConfig} instance. */\nexport async function loadCustomCommands(\n options: LoadCustomCommandsOptions,\n): Promise<CustomCommand[]> {\n return defaultUserConfig.loadCustomCommands(options);\n}\n\n/** Load project instructions via the default {@link UserConfig} instance. */\nexport async function loadProjectInstructions(repoRoot: string): Promise<ProjectInstructions> {\n return defaultUserConfig.loadProjectInstructions(repoRoot);\n}\n","/**\n * Effect Schema definitions for the user-config feature.\n *\n * These schemas are the single source of truth for runtime validation of\n * hook definitions, custom commands, and project instructions at boundaries.\n * The existing implementation in `internal/userConfig.ts` continues to work\n * as-is; these schemas enable gradual adoption of Effect-based validation.\n */\n\nimport { Schema } from \"effect\";\n\n// ---------------------------------------------------------------------------\n// Hook schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for supported hook lifecycle event names.\n */\nexport const HookLifecycleEventSchema = Schema.Literal(\n \"SessionStart\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"Stop\",\n \"SessionEnd\",\n);\n\n/**\n * Hook lifecycle event type derived from the schema.\n */\nexport type HookLifecycleEventFromSchema = Schema.Schema.Type<typeof HookLifecycleEventSchema>;\n\n/**\n * Schema for a hook command — either a single string or an array of strings.\n */\nexport const HookCommandSchema = Schema.Union(Schema.String, Schema.Array(Schema.String));\n\n/**\n * Hook command type derived from the schema.\n */\nexport type HookCommandFromSchema = Schema.Schema.Type<typeof HookCommandSchema>;\n\n/**\n * Schema for a validated hook definition from hooks.json.\n */\nexport const HookDefinitionSchema = Schema.Struct({\n source: Schema.String,\n event: HookLifecycleEventSchema,\n command: HookCommandSchema,\n name: Schema.optional(Schema.String),\n enabled: Schema.Boolean,\n});\n\n/**\n * HookDefinition type derived from the schema.\n */\nexport type HookDefinitionFromSchema = Schema.Schema.Type<typeof HookDefinitionSchema>;\n\n/**\n * Schema for the result of parsing a hooks.json payload.\n */\nexport const ParseHooksResultSchema = Schema.Struct({\n hooks: Schema.Array(HookDefinitionSchema),\n errors: Schema.Array(Schema.String),\n});\n\n/**\n * ParseHooksResult type derived from the schema.\n */\nexport type ParseHooksResultFromSchema = Schema.Schema.Type<typeof ParseHooksResultSchema>;\n\n/**\n * Schema for hook run status.\n */\nexport const HookRunStatusSchema = Schema.Literal(\"skipped\", \"disabled\");\n\n/**\n * Hook run status type derived from the schema.\n */\nexport type HookRunStatusFromSchema = Schema.Schema.Type<typeof HookRunStatusSchema>;\n\n/**\n * Schema for a hook run result.\n */\nexport const HookRunResultSchema = Schema.Struct({\n event: HookLifecycleEventSchema,\n command: HookCommandSchema,\n status: HookRunStatusSchema,\n reason: Schema.Literal(\"hook-command-execution-disabled\", \"hook-disabled\"),\n});\n\n/**\n * HookRunResult type derived from the schema.\n */\nexport type HookRunResultFromSchema = Schema.Schema.Type<typeof HookRunResultSchema>;\n\n// ---------------------------------------------------------------------------\n// Custom command schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for custom command source directory type.\n */\nexport const CustomCommandSourceSchema = Schema.Literal(\"project\", \"user\");\n\n/**\n * Custom command source type derived from the schema.\n */\nexport type CustomCommandSourceFromSchema = Schema.Schema.Type<typeof CustomCommandSourceSchema>;\n\n/**\n * Schema for optional YAML frontmatter metadata in a custom command file.\n */\nexport const CustomCommandMetadataSchema = Schema.Struct({\n description: Schema.optional(Schema.String),\n model: Schema.optional(Schema.String),\n allowedTools: Schema.optional(Schema.Array(Schema.String)),\n});\n\n/**\n * CustomCommandMetadata type derived from the schema.\n */\nexport type CustomCommandMetadataFromSchema = Schema.Schema.Type<\n typeof CustomCommandMetadataSchema\n>;\n\n/**\n * Schema for a loaded custom command ready for rendering.\n */\nexport const CustomCommandSchema = Schema.Struct({\n name: Schema.String,\n filePath: Schema.String,\n source: CustomCommandSourceSchema,\n description: Schema.optional(Schema.String),\n model: Schema.optional(Schema.String),\n allowedTools: Schema.Array(Schema.String),\n promptTemplate: Schema.String,\n});\n\n/**\n * CustomCommand type derived from the schema.\n */\nexport type CustomCommandFromSchema = Schema.Schema.Type<typeof CustomCommandSchema>;\n\n/**\n * Schema for a parsed command file (frontmatter + body).\n */\nexport const ParsedCommandFileSchema = Schema.Struct({\n metadata: CustomCommandMetadataSchema,\n body: Schema.String,\n});\n\n/**\n * ParsedCommandFile type derived from the schema.\n */\nexport type ParsedCommandFileFromSchema = Schema.Schema.Type<typeof ParsedCommandFileSchema>;\n\n// ---------------------------------------------------------------------------\n// Project instruction schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for recognized project instruction file names.\n */\nexport const ProjectInstructionFileNameSchema = Schema.Literal(\"AGENTS.md\", \"CLAUDE.md\");\n\n/**\n * Schema for a project instruction file entry.\n */\nexport const ProjectInstructionFileSchema = Schema.Struct({\n fileName: ProjectInstructionFileNameSchema,\n content: Schema.String,\n});\n\n/**\n * ProjectInstructionFile type derived from the schema.\n */\nexport type ProjectInstructionFileFromSchema = Schema.Schema.Type<\n typeof ProjectInstructionFileSchema\n>;\n\n/**\n * Schema for loaded project instructions.\n */\nexport const ProjectInstructionsSchema = Schema.Struct({\n files: Schema.Array(ProjectInstructionFileSchema),\n promptText: Schema.String,\n});\n\n/**\n * ProjectInstructions type derived from the schema.\n */\nexport type ProjectInstructionsFromSchema = Schema.Schema.Type<typeof ProjectInstructionsSchema>;\n","import { McpServer, type McpServerHandle, type McpServerOptions } from \"./internal/mcpServer.ts\";\n\n/**\n * Start the MCP server with SSE and streamable HTTP transports.\n *\n * Registers all tools from the tool registry and listens for\n * incoming connections from ChatGPT via the Cloudflare tunnel.\n */\nexport function startMcpServer(\n repoRoot: string,\n port: number,\n options: McpServerOptions = {},\n): Promise<McpServerHandle> {\n const server = new McpServer(repoRoot, options);\n return server.start(port).then((url) => ({ url, close: () => server.stop() }));\n}\n","/**\n * Effect Schema versions of tool argument shapes.\n *\n * These mirror the Zod schemas used by the MCP SDK boundary in\n * `internal/mcpServer.ts` and are intended for internal validation,\n * type derivation, and any future Effect-native tool handling.\n *\n * @module\n */\nimport { Schema } from \"effect\";\n\n// ---------------------------------------------------------------------------\n// read_file\n// ---------------------------------------------------------------------------\n\nexport const ReadFileArgsSchema = Schema.Struct({\n path: Schema.String.annotations({ description: \"Repo-relative file path.\" }),\n start_line: Schema.optional(\n Schema.Number.annotations({ description: \"1-based line number to start reading.\" }),\n ),\n max_lines: Schema.optional(\n Schema.Number.annotations({ description: \"Maximum number of lines to read.\" }),\n ),\n});\nexport type ReadFileArgs = Schema.Schema.Type<typeof ReadFileArgsSchema>;\n\n// ---------------------------------------------------------------------------\n// grep_code\n// ---------------------------------------------------------------------------\n\nexport const GrepCodeArgsSchema = Schema.Struct({\n pattern: Schema.String.annotations({ description: \"The ripgrep search pattern.\" }),\n path: Schema.String.annotations({ description: \"Repo-relative path to search.\" }),\n glob: Schema.optional(\n Schema.String.annotations({ description: \"Optional ripgrep glob, e.g. '*.ts'.\" }),\n ),\n});\nexport type GrepCodeArgs = Schema.Schema.Type<typeof GrepCodeArgsSchema>;\n\n// ---------------------------------------------------------------------------\n// apply_patch\n// ---------------------------------------------------------------------------\n\nexport const ApplyPatchArgsSchema = Schema.Struct({\n patch: Schema.String.annotations({\n description: \"Unified diff patch compatible with git apply.\",\n }),\n});\nexport type ApplyPatchArgs = Schema.Schema.Type<typeof ApplyPatchArgsSchema>;\n\n// ---------------------------------------------------------------------------\n// run_tests\n// ---------------------------------------------------------------------------\n\nexport const RunTestsArgsSchema = Schema.Struct({\n command: Schema.String.annotations({\n description: \"Allowed test command, e.g. 'npm test' or 'pytest'.\",\n }),\n});\nexport type RunTestsArgs = Schema.Schema.Type<typeof RunTestsArgsSchema>;\n\n// ---------------------------------------------------------------------------\n// git_diff (no parameters)\n// ---------------------------------------------------------------------------\n\nexport const GitDiffArgsSchema = Schema.Struct({});\nexport type GitDiffArgs = Schema.Schema.Type<typeof GitDiffArgsSchema>;\n\n// ---------------------------------------------------------------------------\n// chatgpt_list_attachments\n// ---------------------------------------------------------------------------\n\nexport const ListAttachmentsArgsSchema = Schema.Struct({\n conversationId: Schema.optional(\n Schema.String.annotations({ description: \"Optional ChatGPT conversation id.\" }),\n ),\n});\nexport type ListAttachmentsArgs = Schema.Schema.Type<typeof ListAttachmentsArgsSchema>;\n\n// ---------------------------------------------------------------------------\n// chatgpt_download_attachment\n// ---------------------------------------------------------------------------\n\nexport const DownloadAttachmentArgsSchema = Schema.Struct({\n conversationId: Schema.optional(\n Schema.String.annotations({ description: \"Optional ChatGPT conversation id.\" }),\n ),\n id: Schema.String.annotations({ description: \"Attachment id from chatgpt_list_attachments.\" }),\n outDir: Schema.optional(\n Schema.String.annotations({\n description:\n \"Optional output directory; defaults to the repo-local .bridge/downloads/<conversationId> (git-ignored).\",\n }),\n ),\n});\nexport type DownloadAttachmentArgs = Schema.Schema.Type<typeof DownloadAttachmentArgsSchema>;\n\n// ---------------------------------------------------------------------------\n// chatgpt_download_all\n// ---------------------------------------------------------------------------\n\nexport const DownloadAllAttachmentsArgsSchema = Schema.Struct({\n conversationId: Schema.optional(\n Schema.String.annotations({ description: \"Optional ChatGPT conversation id.\" }),\n ),\n outDir: Schema.optional(\n Schema.String.annotations({\n description:\n \"Optional output directory; defaults to the repo-local .bridge/downloads/<conversationId> (git-ignored).\",\n }),\n ),\n ids: Schema.optional(\n Schema.Array(Schema.String).annotations({\n description: \"Optional attachment ids to download.\",\n }),\n ),\n});\nexport type DownloadAllAttachmentsArgs = Schema.Schema.Type<\n typeof DownloadAllAttachmentsArgsSchema\n>;\n","/**\n * Effect Schema definitions for the store feature.\n *\n * These schemas are the single source of truth for runtime validation of\n * session metadata, session events, checkpoints, and log entries at boundaries.\n * The existing implementation in `internal/sessionStore.ts` continues to work\n * as-is; these schemas enable gradual adoption of Effect-based validation.\n *\n * @module\n */\nimport { Schema } from \"effect\";\n\n// ---------------------------------------------------------------------------\n// Session schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the role of a transcript message event.\n */\nexport const SessionEventRoleSchema = Schema.Literal(\"user\", \"assistant\", \"system\", \"tool\");\n\n/**\n * SessionEventRole type derived from the schema.\n */\nexport type SessionEventRoleFromSchema = Schema.Schema.Type<typeof SessionEventRoleSchema>;\n\n/**\n * Schema for persisted session metadata.\n */\nexport const SessionMetadataSchema = Schema.Struct({\n id: Schema.String,\n repoPath: Schema.String,\n model: Schema.NullOr(Schema.String),\n contextLimit: Schema.Number,\n tunnelUrl: Schema.NullOr(Schema.String),\n startedAt: Schema.String,\n updatedAt: Schema.String,\n});\n\n/**\n * SessionMetadata type derived from the schema.\n */\nexport type SessionMetadataFromSchema = Schema.Schema.Type<typeof SessionMetadataSchema>;\n\n/**\n * Schema for one persisted session event (message, action, etc.).\n */\nexport const SessionEventSchema = Schema.Struct({\n id: Schema.String,\n type: Schema.String,\n createdAt: Schema.String,\n role: Schema.optional(SessionEventRoleSchema),\n name: Schema.optional(Schema.String),\n status: Schema.optional(Schema.String),\n content: Schema.optional(Schema.String),\n data: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Unknown })),\n});\n\n/**\n * SessionEvent type derived from the schema.\n */\nexport type SessionEventFromSchema = Schema.Schema.Type<typeof SessionEventSchema>;\n\n/**\n * Schema for a loaded session record (metadata + events).\n */\nexport const SessionRecordSchema = Schema.Struct({\n metadata: SessionMetadataSchema,\n events: Schema.Array(SessionEventSchema),\n});\n\n/**\n * SessionRecord type derived from the schema.\n */\nexport type SessionRecordFromSchema = Schema.Schema.Type<typeof SessionRecordSchema>;\n\n// ---------------------------------------------------------------------------\n// Checkpoint schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for checkpoint phase relative to a patch operation.\n */\nexport const CheckpointPhaseSchema = Schema.Literal(\"before\", \"after\");\n\n/**\n * CheckpointPhase type derived from the schema.\n */\nexport type CheckpointPhaseFromSchema = Schema.Schema.Type<typeof CheckpointPhaseSchema>;\n\n/**\n * Schema for a snapshot of one file at checkpoint time.\n */\nexport const CheckpointFileSnapshotSchema = Schema.Struct({\n relativePath: Schema.String,\n exists: Schema.Boolean,\n size: Schema.Number,\n sha256: Schema.optional(Schema.String),\n snapshotRef: Schema.optional(Schema.String),\n});\n\n/**\n * CheckpointFileSnapshot type derived from the schema.\n */\nexport type CheckpointFileSnapshotFromSchema = Schema.Schema.Type<\n typeof CheckpointFileSnapshotSchema\n>;\n\n/**\n * Schema for a full checkpoint record persisted on disk.\n */\nexport const CheckpointSchema = Schema.Struct({\n id: Schema.String,\n repoRoot: Schema.String,\n createdAt: Schema.String,\n phase: CheckpointPhaseSchema,\n label: Schema.optional(Schema.String),\n files: Schema.Array(CheckpointFileSnapshotSchema),\n});\n\n/**\n * Checkpoint type derived from the schema.\n */\nexport type CheckpointFromSchema = Schema.Schema.Type<typeof CheckpointSchema>;\n\n/**\n * Schema for a checkpoint summary row.\n */\nexport const CheckpointSummarySchema = Schema.Struct({\n id: Schema.String,\n createdAt: Schema.String,\n phase: CheckpointPhaseSchema,\n fileCount: Schema.Number,\n label: Schema.optional(Schema.String),\n});\n\n/**\n * CheckpointSummary type derived from the schema.\n */\nexport type CheckpointSummaryFromSchema = Schema.Schema.Type<typeof CheckpointSummarySchema>;\n\n// ---------------------------------------------------------------------------\n// Logging schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for a bridge log event.\n */\nexport const BridgeLogEventSchema = Schema.Struct({\n repoPath: Schema.String,\n type: Schema.String,\n data: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Unknown })),\n});\n\n/**\n * BridgeLogEvent type derived from the schema.\n */\nexport type BridgeLogEventFromSchema = Schema.Schema.Type<typeof BridgeLogEventSchema>;\n\n/**\n * Schema for a persisted bridge log line (as written to JSONL).\n */\nexport const BridgeLogLineSchema = Schema.Struct({\n ts: Schema.String,\n repoPath: Schema.String,\n type: Schema.String,\n data: Schema.Record({ key: Schema.String, value: Schema.Unknown }),\n});\n\n/**\n * BridgeLogLine type derived from the schema.\n */\nexport type BridgeLogLineFromSchema = Schema.Schema.Type<typeof BridgeLogLineSchema>;\n\n// ---------------------------------------------------------------------------\n// File resolver schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for a resolved @file mention result.\n */\nexport const ResolvedFileSchema = Schema.Struct({\n relPath: Schema.String,\n content: Schema.String,\n});\n\n/**\n * ResolvedFile type derived from the schema.\n */\nexport type ResolvedFileFromSchema = Schema.Schema.Type<typeof ResolvedFileSchema>;\n","import type { BrowserProvider } from \"./browserProviderTypes.ts\";\nimport { ChatGptPage } from \"./chatgpt/chatgptPage.ts\";\n\nconst chatGptPage = new ChatGptPage();\n\n/** ChatGPT browser adapter configuration. */\nexport const CHATGPT_PROVIDER: BrowserProvider = {\n id: chatGptPage.id,\n origin: chatGptPage.origin,\n defaultUrl: chatGptPage.defaultUrl,\n defaultModel: chatGptPage.defaultModel,\n displayName: chatGptPage.displayName,\n composerSelector: chatGptPage.composerSelector,\n supportsMcpConnector: chatGptPage.supportsMcpConnector,\n assertSignedIn: chatGptPage.assertSignedIn.bind(chatGptPage),\n injectPrompt: chatGptPage.injectPrompt.bind(chatGptPage),\n waitForResponse: chatGptPage.waitForResponse.bind(chatGptPage),\n captureLastResponse: chatGptPage.captureLastResponse.bind(chatGptPage),\n countAssistantResponses: chatGptPage.countAssistantResponses.bind(chatGptPage),\n captureAllMessages: chatGptPage.captureAllMessages.bind(chatGptPage),\n readSidebarConversations: chatGptPage.readSidebarConversations.bind(chatGptPage),\n navigateToConversation: chatGptPage.navigateToConversation.bind(chatGptPage),\n newConversation: chatGptPage.newConversation.bind(chatGptPage),\n detectCurrentModel: chatGptPage.detectCurrentModel.bind(chatGptPage),\n listAvailableModels: chatGptPage.listAvailableModels.bind(chatGptPage),\n selectModel: chatGptPage.selectModel.bind(chatGptPage),\n rewindLastUserPrompt: chatGptPage.rewindLastUserPrompt.bind(chatGptPage),\n stopGenerating: chatGptPage.stopGenerating.bind(chatGptPage),\n attachFilesToPrompt: chatGptPage.attachFilesToPrompt.bind(chatGptPage),\n isLikelyModelLabel: chatGptPage.isLikelyModelLabel.bind(chatGptPage),\n setupMcpConnector: chatGptPage.setupMcpConnector.bind(chatGptPage),\n};\n","import type { ConnectorSetupOptions, ConnectorSetupResult } from \"@/features/domain\";\nimport type { Page } from \"playwright\";\n\n/** Default display name for the bridge's connector inside Claude. */\nconst DEFAULT_CONNECTOR_NAME = \"ai-browser-bridge\";\n\n/** Open Settings → Connectors from the account menu. */\nasync function openConnectorsPanel(page: Page, steps: string[]): Promise<void> {\n await page.locator('[data-testid=\"user-menu-button\"]').first().click({ timeout: 10_000 });\n await page.locator('[data-testid=\"user-menu-settings\"]').first().click({ timeout: 10_000 });\n await page\n .locator('[role=\"tab\"], [role=\"menuitem\"], [role=\"dialog\"] a[href], [role=\"dialog\"] button')\n .filter({ hasText: /connectors/i })\n .first()\n .click({ timeout: 10_000 });\n await page.waitForTimeout(800);\n steps.push(\"Opened Settings → Connectors.\");\n}\n\n/** Whether a connector with this name is already listed on the panel. */\nasync function connectorExists(page: Page, name: string): Promise<boolean> {\n const match = page.locator('[role=\"dialog\"]').getByText(name, { exact: false });\n return (await match.count().catch(() => 0)) > 0;\n}\n\n/** Open the custom-connector form via Add connector → Add custom connector. */\nasync function openCustomForm(page: Page, steps: string[]): Promise<void> {\n await page.locator('button[aria-label=\"Add connector\"]').first().click({ timeout: 10_000 });\n await page\n .getByRole(\"menuitem\", { name: /add custom connector/i })\n .first()\n .click({ timeout: 10_000 });\n await page.waitForTimeout(600);\n steps.push(\"Opened the custom-connector form.\");\n}\n\n/** Fill the connector name + remote MCP server URL fields. */\nasync function fillForm(page: Page, name: string, url: string, steps: string[]): Promise<void> {\n await page.locator('input[placeholder=\"Name\"]').first().fill(name);\n await page.locator('input[placeholder=\"Remote MCP server URL\"]').first().fill(url);\n steps.push(`Filled name \"${name}\" and the connector URL.`);\n}\n\n/** Submit the form and accept any unverified-connector confirmation. */\nasync function submitForm(page: Page, result: ConnectorSetupResult): Promise<void> {\n const add = page\n .locator('[role=\"dialog\"] button[type=\"submit\"], [role=\"dialog\"] button')\n .filter({ hasText: /^add$/i });\n const clicked = await add\n .first()\n .click({ timeout: 8_000 })\n .then(() => true)\n .catch(() => false);\n if (!clicked) {\n result.warnings.push(\"Filled the connector form but could not click Add.\");\n return;\n }\n await page.waitForTimeout(1_500);\n const confirm = page.getByRole(\"button\", { name: /add anyway|confirm|continue|^connect$/i });\n if (\n await confirm\n .first()\n .isVisible({ timeout: 3_000 })\n .catch(() => false)\n ) {\n await confirm\n .first()\n .click({ timeout: 5_000 })\n .catch(() => undefined);\n result.steps.push(\"Accepted the unverified-connector confirmation.\");\n }\n result.completed = true;\n result.steps.push(\"Submitted the connector form.\");\n}\n\n/** Close the settings dialog. */\nasync function closeSettings(page: Page): Promise<void> {\n await page\n .locator('[role=\"dialog\"] button[aria-label=\"Close\"]')\n .first()\n .click({ timeout: 4_000 })\n .catch(() => undefined);\n await page.keyboard.press(\"Escape\").catch(() => undefined);\n}\n\n/**\n * Register the bridge's MCP server as a custom connector in Claude web\n * (account menu → Settings → Connectors → Add custom connector). Accumulates\n * human-readable steps/warnings like the ChatGPT flow, and — when `automatic` is\n * false — fills the form but leaves it unsubmitted for manual review.\n */\nexport async function setupMcpConnectorInClaude(\n page: Page,\n connectorUrl: string,\n options: ConnectorSetupOptions = {},\n): Promise<ConnectorSetupResult> {\n const connectorName = options.connectorName ?? DEFAULT_CONNECTOR_NAME;\n const result: ConnectorSetupResult = { connectorUrl, completed: false, steps: [], warnings: [] };\n try {\n await openConnectorsPanel(page, result.steps);\n if (await connectorExists(page, connectorName)) {\n result.completed = true;\n result.steps.push(`Connector \"${connectorName}\" is already installed.`);\n await closeSettings(page);\n return result;\n }\n await openCustomForm(page, result.steps);\n await fillForm(page, connectorName, connectorUrl, result.steps);\n if (options.automatic === false) {\n result.steps.push(\n \"Left the form filled but unsubmitted for manual review (automatic=false).\",\n );\n return result;\n }\n await submitForm(page, result);\n await closeSettings(page);\n } catch (err) {\n result.warnings.push(`Claude connector setup did not finish: ${String(err).split(\"\\n\")[0]}`);\n }\n return result;\n}\n","import { PROVIDER_CONFIG } from \"@/config\";\nimport type { ModelOption } from \"@/features/domain\";\nimport type { Locator, Page } from \"playwright\";\nimport type { BrowserProvider, ResponseWaitOptions } from \"../browserProviderTypes.ts\";\nimport { GuestSessionError } from \"../guestSessionError.ts\";\n\n/** Normalize whitespace in display text scraped from the DOM. */\nfunction normalizeDisplayText(value: string): string {\n return value\n .replace(/\\u00a0/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n// --- capture-response.dom-snippet.ts ---\nconst CAPTURE_ALL_MESSAGES_SNIPPET = String.raw`(() => {\n const messages = [];\n const userNodes = document.querySelectorAll(\"user-query, .query-text, .user-query, [data-message-author='user']\");\n const assistantNodes = document.querySelectorAll(\"model-response, message-content, .model-response-text, .response-content\");\n const turns = [];\n userNodes.forEach((node, index) => turns.push({ role: \"user\", node, index }));\n assistantNodes.forEach((node, index) => turns.push({ role: \"assistant\", node, index }));\n turns.sort((a, b) => {\n const position = a.node.compareDocumentPosition(b.node);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;\n if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;\n return a.index - b.index;\n });\n for (const turn of turns) {\n const content = turn.node.innerText?.trim() ?? \"\";\n if (content) messages.push({ role: turn.role, content });\n }\n return messages;\n})()`;\n\n// --- capture-response.ts ---\n\nfunction stripGeminiResponseHeading(text: string): string {\n return text.replace(/^Gemini said\\s*/i, \"\").trim();\n}\n\n/** Extract the text content of the last assistant response. */\nasync function captureLastResponse(page: Page): Promise<string> {\n const blocks = page.locator(SELECTORS.responseBlock);\n const count = await blocks.count();\n if (count === 0) return \"\";\n const text = normalizeDisplayText(\n await blocks\n .nth(count - 1)\n .innerText()\n .catch(() => \"\"),\n );\n return stripGeminiResponseHeading(text);\n}\n\n/** Count assistant responses currently rendered in the conversation. */\nasync function countAssistantResponses(page: Page): Promise<number> {\n return page.locator(SELECTORS.responseBlock).count();\n}\n\n/** Extract all messages from the current conversation in DOM order. */\nasync function captureAllMessages(page: Page): Promise<Array<{ role: string; content: string }>> {\n return page.evaluate(CAPTURE_ALL_MESSAGES_SNIPPET);\n}\n\n// --- gemini-actions.ts ---\n\n/** Gemini web does not expose ChatGPT-style prompt rewind; fail clearly. */\nasync function rewindLastUserPrompt(_page: Page, _replacement?: string): Promise<void> {\n throw new Error(\"Rewind is not supported on gemini.google.com yet.\");\n}\n\n/** Stop the active Gemini response stream when possible. */\nasync function stopGenerating(page: Page, timeout = 5_000): Promise<boolean> {\n const stop = page.locator('button[aria-label*=\"Stop\" i]').first();\n if (!(await stop.isVisible({ timeout: 1_000 }).catch(() => false))) return false;\n await stop.click({ timeout });\n return true;\n}\n\n/** Attach local files to the Gemini composer when a file input is available. */\nasync function attachFilesToPrompt(page: Page, paths: string[]): Promise<void> {\n if (paths.length === 0) return;\n const directInput = page.locator(SELECTORS.attachmentInput).first();\n if ((await directInput.count()) > 0) {\n await directInput.setInputFiles(paths);\n return;\n }\n await attachViaButton({ page, paths });\n}\n\nasync function attachViaButton(input: { page: Page; paths: string[] }): Promise<void> {\n const attachButton = input.page.locator(SELECTORS.attachmentButton).first();\n if (!(await attachButton.isVisible({ timeout: 2_000 }).catch(() => false))) {\n throw new Error(\"Gemini file attachment controls are not available on this page.\");\n }\n await attachButton.click();\n await setAttachmentFiles(input);\n}\n\nasync function setAttachmentFiles(input: { page: Page; paths: string[] }): Promise<void> {\n const fileInput = input.page.locator(SELECTORS.attachmentInput).first();\n await fileInput.waitFor({ state: \"attached\", timeout: 5_000 });\n await fileInput.setInputFiles(input.paths);\n}\n\n// --- gemini-model.helpers.ts ---\n/** True when a string looks like a real Gemini model name. */\nfunction isLikelyModelLabel(value: string): boolean {\n return /\\b(gemini|flash|pro|thinking|advanced|experimental)\\b/i.test(value);\n}\n\n// --- gemini-model.picker.ts ---\n\nasync function readModelFromTrigger(trigger: Locator): Promise<string> {\n const text = normalizeDisplayText(await trigger.innerText().catch(() => \"\"));\n const line = text.split(\"\\n\").find((part) => isLikelyModelLabel(part));\n if (line) return line;\n return readTriggerAriaLabel(trigger);\n}\n\nasync function readTriggerAriaLabel(trigger: Locator): Promise<string> {\n const ariaLabel = await trigger.getAttribute(\"aria-label\").catch(() => null);\n if (ariaLabel && isLikelyModelLabel(ariaLabel)) return ariaLabel.trim();\n return \"Gemini\";\n}\n\nasync function collectMenuModels(page: Page): Promise<ModelOption[]> {\n const items = page.locator(\n `${SELECTORS.openMenu} [role=\"menuitem\"], ${SELECTORS.openMenu} [role=\"option\"]`,\n );\n const count = await items.count();\n const models: ModelOption[] = [];\n for (let i = 0; i < count; i += 1) {\n const model = await readMenuItemModel(items.nth(i));\n if (model) models.push(model);\n }\n return models;\n}\n\nasync function readMenuItemModel(item: Locator): Promise<ModelOption | null> {\n const label = normalizeDisplayText(await item.innerText().catch(() => \"\"));\n if (!label || !isLikelyModelLabel(label)) return null;\n const selected =\n (await item.getAttribute(\"aria-checked\").catch(() => null)) === \"true\" ||\n (await item.getAttribute(\"aria-selected\").catch(() => null)) === \"true\";\n return { id: label.toLowerCase().replace(/\\s+/g, \"-\"), label, selected: !!selected };\n}\n\nasync function firstVisible(params: { page: Page; selector: string }): Promise<Locator | null> {\n const locator = params.page.locator(params.selector);\n const count = await locator.count();\n for (let i = 0; i < count; i += 1) {\n const candidate = locator.nth(i);\n if (await candidate.isVisible().catch(() => false)) return candidate;\n }\n return null;\n}\n\n// --- gemini-model.ts ---\n\n/** Detect the currently selected Gemini model from the page DOM. */\nasync function detectCurrentModel(page: Page): Promise<string> {\n try {\n const trigger = await firstVisible({ page, selector: SELECTORS.modelTrigger });\n if (!trigger) return \"Gemini\";\n return await readModelFromTrigger(trigger);\n } catch {\n return \"Gemini\";\n }\n}\n\n/** List models exposed by Gemini's model picker when it can be opened. */\nasync function listAvailableModels(page: Page): Promise<ModelOption[]> {\n const trigger = await firstVisible({ page, selector: SELECTORS.modelTrigger });\n if (!trigger) return [];\n return collectModelsFromOpenMenu({ page, trigger });\n}\n\nasync function collectModelsFromOpenMenu(input: { page: Page; trigger: Locator }): Promise<\n ModelOption[]\n> {\n await input.trigger.click().catch(() => {});\n await input.page.waitForSelector(SELECTORS.openMenu, { timeout: 3_000 }).catch(() => {});\n const models = await collectMenuModels(input.page);\n await input.page.keyboard.press(\"Escape\").catch(() => {});\n return models;\n}\n\n/** Switch Gemini to a model exposed by the browser model picker. */\nasync function selectModel(page: Page, query: string): Promise<string> {\n const match = await findModelMatch({ page, query });\n await clickModelMenuItem({ page, label: match.label });\n return match.label;\n}\n\nasync function clickModelMenuItem(input: { page: Page; label: string }): Promise<void> {\n const trigger = await firstVisible({ page: input.page, selector: SELECTORS.modelTrigger });\n if (!trigger) throw new Error(\"Gemini model picker is not available.\");\n await trigger.click();\n await selectMenuModelItem(input);\n}\n\nasync function selectMenuModelItem(input: { page: Page; label: string }): Promise<void> {\n await input.page.waitForSelector(SELECTORS.openMenu, { timeout: 3_000 });\n await input.page\n .locator(`${SELECTORS.openMenu} [role=\"menuitem\"], ${SELECTORS.openMenu} [role=\"option\"]`)\n .filter({ hasText: input.label })\n .first()\n .click();\n await input.page.keyboard.press(\"Escape\").catch(() => {});\n}\n\nasync function findModelMatch(input: { page: Page; query: string }): Promise<ModelOption> {\n const models = await listAvailableModels(input.page);\n const normalizedQuery = input.query.trim().toLowerCase();\n const match = models.find(\n (model) =>\n model.label.toLowerCase().includes(normalizedQuery) ||\n model.id.includes(normalizedQuery.replace(/\\s+/g, \"-\")),\n );\n if (!match) throw new Error(`Model not found in Gemini picker: ${input.query}`);\n return match;\n}\n\n// --- gemini-navigation.ts ---\n\n/** True when Gemini is showing the unauthenticated shell. */\nasync function isGuestSession(page: Page): Promise<boolean> {\n const input = page.locator(SELECTORS.promptInput).first();\n if (await input.isVisible({ timeout: 2500 }).catch(() => false)) return false;\n const signIn = page.locator(SELECTORS.signInButton).first();\n return signIn.isVisible({ timeout: 1500 }).catch(() => true);\n}\n\n/** Fail fast before sending a prompt to an unauthenticated session. */\nasync function assertSignedIn(page: Page): Promise<void> {\n if (await isGuestSession(page)) {\n throw new GuestSessionError(\n \"Gemini is not signed in. \" +\n \"This is the bridge's isolated Chrome — not your daily browser. \" +\n \"Click Sign in in that window, complete Google sign-in, leave it open, then run again.\",\n );\n }\n}\n\n/** Read the conversation list from Gemini's sidebar when available. */\nasync function readSidebarConversations(\n page: Page,\n): Promise<Array<{ id: string; title: string; url: string }>> {\n const links = await page.locator(SELECTORS.sidebarConversation).all();\n const conversations: Array<{ id: string; title: string; url: string }> = [];\n for (const link of links) {\n const href = await link.getAttribute(\"href\");\n const title = normalizeDisplayText(await link.innerText().catch(() => \"\"));\n if (!href || !title) continue;\n conversations.push(buildConversationEntry({ href, title }));\n }\n return conversations;\n}\n\n/** Navigate to a specific Gemini conversation by URL. */\nasync function navigateToConversation(page: Page, url: string): Promise<void> {\n await page.goto(url);\n await page.waitForSelector(SELECTORS.promptInput, { timeout: 30_000 });\n}\n\n/** Start a new Gemini conversation. */\nasync function newConversation(page: Page): Promise<void> {\n await page.goto(\"https://gemini.google.com/app\");\n await page.waitForSelector(SELECTORS.promptInput, { timeout: 30_000 });\n}\n\nfunction buildConversationEntry(input: { href: string; title: string }): {\n id: string;\n title: string;\n url: string;\n} {\n const url = input.href.startsWith(\"http\") ? input.href : `https://gemini.google.com${input.href}`;\n const id = input.href.split(\"/\").filter(Boolean).pop() ?? input.href;\n return { id, title: input.title, url };\n}\n\n// --- inject-prompt.ts ---\n\n/** Type a prompt into Gemini's composer and confirm it was sent. */\nasync function injectPrompt(page: Page, text: string): Promise<void> {\n await page.bringToFront().catch(() => {});\n const input = page.locator(SELECTORS.promptInput).first();\n for (let attempt = 0; attempt < 3; attempt += 1) {\n await fillAndSend({ page, input, text });\n if (await composerClears({ page })) return;\n }\n throw new Error(\"injectPrompt: composer never cleared after 3 send attempts\");\n}\n\nasync function fillAndSend(params: { page: Page; input: Locator; text: string }): Promise<void> {\n await params.input.click();\n await params.input.fill(params.text);\n await params.input.dispatchEvent(\"input\");\n await clickSendOrEnter(params.page);\n}\n\nasync function clickSendOrEnter(page: Page): Promise<void> {\n const sendBtn = page.locator(SELECTORS.sendButton).first();\n try {\n await sendBtn.waitFor({ state: \"visible\", timeout: 5_000 });\n await sendBtn.click();\n } catch {\n await page.keyboard.press(\"Enter\");\n }\n}\n\nasync function composerClears(params: { page: Page }): Promise<boolean> {\n for (let poll = 0; poll < 10; poll += 1) {\n if ((await readComposerText(params.page)) === \"\") return true;\n await params.page.waitForTimeout(500);\n }\n return false;\n}\n\nasync function readComposerText(page: Page): Promise<string> {\n return page.evaluate(() => {\n const editor = document.querySelector<HTMLElement>(\n \"div.ql-editor, [contenteditable='true'][role='textbox']\",\n );\n return (editor?.innerText ?? \"\").trim();\n });\n}\n\n// --- selectors.config.ts ---\n/** DOM selectors for Gemini's web interface. Subject to change when Google updates UI. */\nconst SELECTORS = {\n promptInput: [\n \"div.ql-editor\",\n 'rich-textarea [contenteditable=\"true\"]',\n '[aria-label=\"Enter a prompt here\"]',\n '[contenteditable=\"true\"][role=\"textbox\"]',\n ].join(\", \"),\n sendButton: [\n 'button[aria-label=\"Send message\"]',\n 'button[aria-label*=\"Send\" i]',\n \".send-button\",\n \"button.send-button\",\n ].join(\", \"),\n responseBlock: PROVIDER_CONFIG.gemini.selectors.assistant,\n userBlock: [\"user-query\", \".query-text\", \".user-query\", '[data-message-author=\"user\"]'].join(\n \", \",\n ),\n streamingIndicator: ['[aria-busy=\"true\"]', 'button[aria-label*=\"Stop\" i]'].join(\", \"),\n sidebarConversation: ['a[href*=\"/app/\"]', 'nav a[href*=\"gemini.google.com\"]'].join(\", \"),\n modelTrigger: [\n 'button[aria-label*=\"model\" i]',\n 'button[aria-label*=\"Model\" i]',\n '[data-test-id=\"model-selector\"]',\n 'button:has-text(\"Gemini\")',\n 'button:has-text(\"Flash\")',\n 'button:has-text(\"Pro\")',\n ].join(\", \"),\n openMenu: '[role=\"menu\"], [role=\"listbox\"], mat-menu-panel',\n signInButton: [\n 'a[href*=\"accounts.google.com\"]',\n 'button:has-text(\"Sign in\")',\n '[aria-label*=\"Sign in\" i]',\n ].join(\", \"),\n attachmentInput: 'input[type=\"file\"]',\n attachmentButton: [\n 'button[aria-label*=\"Upload\" i]',\n 'button[aria-label*=\"Attach\" i]',\n 'button[aria-label*=\"Add file\" i]',\n ].join(\", \"),\n actionButtons: [\n 'button[aria-label=\"Redo\"]',\n 'button[aria-label=\"Copy\"]',\n 'button[aria-label=\"Show more options\"]',\n ].join(\", \"),\n} as const;\n\n// --- wait-response.helpers.ts ---\n\n/** Parsed timeout and baseline fields for Gemini response waits. */\ninterface ParsedWaitOptions {\n timeout: number;\n previousAssistantCount?: number;\n previousLastAssistantText?: string;\n}\n\nfunction parseWaitOptions(\n options:\n | number\n | {\n timeout?: number;\n previousAssistantCount?: number;\n previousLastAssistantText?: string;\n },\n): ParsedWaitOptions {\n if (typeof options === \"number\") return { timeout: options };\n return {\n timeout: options.timeout ?? 300_000,\n previousAssistantCount: options.previousAssistantCount,\n previousLastAssistantText: normalizeDisplayText(options.previousLastAssistantText ?? \"\"),\n };\n}\n\nfunction remainingTimeout(startedAt: number, timeout: number): number {\n return Math.max(1_000, timeout - (Date.now() - startedAt));\n}\n\nfunction isTransientAssistantText(text: string): boolean {\n const normalized = text.trim().toLowerCase();\n return (\n normalized === \"thinking\" ||\n normalized.endsWith(\" thinking\") ||\n normalized.endsWith(\" thinking...\") ||\n /^thinking[.\\s]*$/.test(normalized)\n );\n}\n\nasync function waitForResponseAfterBaseline(page: Page, options: ParsedWaitOptions): Promise<void> {\n const startedAt = Date.now();\n while (Date.now() - startedAt < options.timeout) {\n if (await baselineAdvanced({ page, options })) return;\n await page.waitForTimeout(250);\n }\n throw new Error(\"Timed out waiting for Gemini to start a new response.\");\n}\n\nasync function baselineAdvanced(input: {\n page: Page;\n options: ParsedWaitOptions;\n}): Promise<boolean> {\n if (await hasStreamingIndicator(input.page)) return true;\n if (await assistantCountAdvanced(input)) return true;\n return lastAssistantTextAdvanced(input);\n}\n\nasync function hasStreamingIndicator(page: Page): Promise<boolean> {\n return page\n .locator(SELECTORS.streamingIndicator)\n .first()\n .isVisible()\n .catch(() => false);\n}\n\nasync function assistantCountAdvanced(input: {\n page: Page;\n options: ParsedWaitOptions;\n}): Promise<boolean> {\n if (input.options.previousAssistantCount === undefined) return false;\n const count = await countAssistantResponses(input.page);\n return count > input.options.previousAssistantCount;\n}\n\nasync function lastAssistantTextAdvanced(input: {\n page: Page;\n options: ParsedWaitOptions;\n}): Promise<boolean> {\n const lastText = normalizeDisplayText(await captureLastResponse(input.page).catch(() => \"\"));\n return (\n !!input.options.previousLastAssistantText &&\n !!lastText &&\n lastText !== input.options.previousLastAssistantText\n );\n}\n\n// --- wait-response.ts ---\n\n/** Quiet window a plain text turn must hold before it counts as settled. */\nconst SETTLE_QUIET_MS = 1_500;\n\n/**\n * Decide whether the current assistant turn has finished producing output.\n * Pure helper so completion policy is unit-testable without a browser.\n */\nfunction isTurnSettled(state: {\n hasText: boolean;\n isTransientText: boolean;\n streaming: boolean;\n stableForMs: number;\n}): boolean {\n if (state.streaming) return false;\n if (state.stableForMs < SETTLE_QUIET_MS) return false;\n return state.hasText && !state.isTransientText;\n}\n\n/** Wait for Gemini to finish streaming its response. */\nasync function waitForResponse(\n page: Page,\n options: number | ResponseWaitOptions = {},\n): Promise<void> {\n const parsed = parseWaitOptions(options);\n const startedAt = Date.now();\n await waitForInitialResponse({ page, parsed });\n await waitForStreamingEnd({ page, startedAt, timeout: parsed.timeout });\n await waitForLastAssistantTextStable({\n page,\n timeout: remainingTimeout(startedAt, parsed.timeout),\n });\n}\n\nasync function waitForInitialResponse(input: {\n page: Page;\n parsed: ParsedWaitOptions;\n}): Promise<void> {\n if (input.parsed.previousAssistantCount !== undefined || input.parsed.previousLastAssistantText) {\n await waitForResponseAfterBaseline(input.page, input.parsed);\n return;\n }\n await input.page.waitForSelector(SELECTORS.responseBlock, { timeout: input.parsed.timeout });\n}\n\nasync function waitForStreamingEnd(input: {\n page: Page;\n startedAt: number;\n timeout: number;\n}): Promise<void> {\n try {\n const indicator = input.page.locator(SELECTORS.streamingIndicator).first();\n await indicator.waitFor({ state: \"visible\", timeout: 10_000 });\n await indicator.waitFor({\n state: \"hidden\",\n timeout: remainingTimeout(input.startedAt, input.timeout),\n });\n } catch {\n // Response might already be complete\n }\n}\n\nasync function waitForLastAssistantTextStable(input: {\n page: Page;\n timeout: number;\n}): Promise<void> {\n const startedAt = Date.now();\n let lastText = \"\";\n let stableSince = Date.now();\n while (Date.now() - startedAt < input.timeout) {\n const snapshot = await readStabilitySnapshot(input.page);\n if (snapshot.text !== lastText) {\n lastText = snapshot.text;\n stableSince = Date.now();\n }\n if (\n isTurnSettled({\n hasText: !!snapshot.text,\n isTransientText: isTransientAssistantText(snapshot.text),\n streaming: snapshot.streaming,\n stableForMs: Date.now() - stableSince,\n })\n )\n return;\n await input.page.waitForTimeout(500);\n }\n throw new Error(\"Timed out waiting for Gemini response to settle.\");\n}\n\nasync function readStabilitySnapshot(page: Page): Promise<{ text: string; streaming: boolean }> {\n const text = normalizeDisplayText(await captureLastResponse(page).catch(() => \"\"));\n const streaming = await page\n .locator(SELECTORS.streamingIndicator)\n .first()\n .isVisible()\n .catch(() => false);\n return { text, streaming };\n}\n\nexport class GeminiPage implements BrowserProvider {\n readonly id = \"gemini\" as const;\n readonly origin = \"gemini.google.com\";\n readonly defaultUrl = \"https://gemini.google.com/app\";\n readonly defaultModel = \"Gemini\";\n readonly displayName = \"Gemini\";\n readonly composerSelector = PROVIDER_CONFIG.gemini.selectors.composer;\n readonly supportsMcpConnector = false;\n\n /** Fail fast when Gemini is not signed in. */\n async assertSignedIn(page: Page): Promise<void> {\n return assertSignedIn(page);\n }\n /** Type a prompt into the composer and send it. */\n async injectPrompt(page: Page, text: string): Promise<void> {\n return injectPrompt(page, text);\n }\n /** Wait until the assistant response finishes streaming. */\n async waitForResponse(page: Page, options?: number | ResponseWaitOptions): Promise<void> {\n return waitForResponse(page, options);\n }\n /** Read the last assistant response text from the page. */\n async captureLastResponse(page: Page): Promise<string> {\n return captureLastResponse(page);\n }\n /** Count rendered assistant response blocks. */\n async countAssistantResponses(page: Page): Promise<number> {\n return countAssistantResponses(page);\n }\n /** Capture all conversation messages from the DOM. */\n async captureAllMessages(page: Page): Promise<Array<{ role: string; content: string }>> {\n return captureAllMessages(page);\n }\n /** Read conversation entries from the sidebar. */\n async readSidebarConversations(\n page: Page,\n ): Promise<Array<{ id: string; title: string; url: string }>> {\n return readSidebarConversations(page);\n }\n /** Navigate to a conversation URL. */\n async navigateToConversation(page: Page, url: string): Promise<void> {\n return navigateToConversation(page, url);\n }\n /** Open a new Gemini conversation. */\n async newConversation(page: Page): Promise<void> {\n return newConversation(page);\n }\n /** Detect the currently selected model label. */\n async detectCurrentModel(page: Page): Promise<string> {\n return detectCurrentModel(page);\n }\n /** List models exposed in the model picker. */\n async listAvailableModels(page: Page): Promise<ModelOption[]> {\n return listAvailableModels(page);\n }\n /** Switch to a model matching the query string. */\n async selectModel(page: Page, query: string): Promise<string> {\n return selectModel(page, query);\n }\n /** Rewind is not supported on Gemini web yet. */\n async rewindLastUserPrompt(page: Page, replacement?: string): Promise<void> {\n return rewindLastUserPrompt(page, replacement);\n }\n /** Stop an in-progress response stream when possible. */\n async stopGenerating(page: Page, timeout?: number): Promise<boolean> {\n return stopGenerating(page, timeout);\n }\n /** Attach local files to the composer. */\n async attachFilesToPrompt(page: Page, paths: string[]): Promise<void> {\n return attachFilesToPrompt(page, paths);\n }\n /** True when a string looks like a Gemini model label. */\n isLikelyModelLabel(value: string): boolean {\n return isLikelyModelLabel(value);\n }\n}\n\nexport { injectPrompt, isLikelyModelLabel, isTurnSettled, SELECTORS };\n","import type { BrowserProvider } from \"./browserProviderTypes.ts\";\nimport { GeminiPage } from \"./gemini/geminiPage.ts\";\n\nconst geminiPage = new GeminiPage();\n\n/** Gemini browser adapter configuration. */\nexport const GEMINI_PROVIDER: BrowserProvider = {\n id: geminiPage.id,\n origin: geminiPage.origin,\n defaultUrl: geminiPage.defaultUrl,\n defaultModel: geminiPage.defaultModel,\n displayName: geminiPage.displayName,\n composerSelector: geminiPage.composerSelector,\n supportsMcpConnector: geminiPage.supportsMcpConnector,\n assertSignedIn: geminiPage.assertSignedIn.bind(geminiPage),\n injectPrompt: geminiPage.injectPrompt.bind(geminiPage),\n waitForResponse: geminiPage.waitForResponse.bind(geminiPage),\n captureLastResponse: geminiPage.captureLastResponse.bind(geminiPage),\n countAssistantResponses: geminiPage.countAssistantResponses.bind(geminiPage),\n captureAllMessages: geminiPage.captureAllMessages.bind(geminiPage),\n readSidebarConversations: geminiPage.readSidebarConversations.bind(geminiPage),\n navigateToConversation: geminiPage.navigateToConversation.bind(geminiPage),\n newConversation: geminiPage.newConversation.bind(geminiPage),\n detectCurrentModel: geminiPage.detectCurrentModel.bind(geminiPage),\n listAvailableModels: geminiPage.listAvailableModels.bind(geminiPage),\n selectModel: geminiPage.selectModel.bind(geminiPage),\n rewindLastUserPrompt: geminiPage.rewindLastUserPrompt.bind(geminiPage),\n stopGenerating: geminiPage.stopGenerating.bind(geminiPage),\n attachFilesToPrompt: geminiPage.attachFilesToPrompt.bind(geminiPage),\n isLikelyModelLabel: geminiPage.isLikelyModelLabel.bind(geminiPage),\n};\n","import { DEFAULT_ASK_TIMEOUT_SECONDS } from \"@/config\";\nimport type { ProviderConfigEntry } from \"@/config\";\nimport type { ConnectorSetupOptions, ConnectorSetupResult, ModelOption } from \"@/features/domain\";\nimport type { Page } from \"playwright\";\nimport type { BrowserProvider, ResponseWaitOptions } from \"./browserProviderTypes.ts\";\n\n/** A provider config entry plus its resolved id — the input to the generic adapter. */\nexport type WebChatProfile = ProviderConfigEntry & { id: string };\n\n/** Provider-specific MCP connector setup, injected for providers that support it. */\nexport type ConnectorSetupFn = (\n page: Page,\n url: string,\n options?: ConnectorSetupOptions,\n) => Promise<ConnectorSetupResult>;\n\nconst MODEL_KEYWORDS = [\n \"gpt\",\n \"claude\",\n \"gemini\",\n \"grok\",\n \"deepseek\",\n \"sonar\",\n \"opus\",\n \"sonnet\",\n \"haiku\",\n \"reasoner\",\n \"flash\",\n];\n\n/** First display line of a text block (safe under noUncheckedIndexedAccess). */\nfunction firstLine(text: string): string {\n return (text.trim().split(\"\\n\")[0] ?? \"\").trim();\n}\n\n/**\n * Best-effort generic adapter for a plain web-chat provider (composer + streamed\n * assistant replies), driven entirely by a {@link WebChatProfile} selector set.\n *\n * LIVE-VERIFY: the selectors each provider passes are a starting point and must be\n * checked against the real, signed-in DOM. Functional operations (sidebar history,\n * model detection, new chat, file attach) light up per provider as the optional\n * selectors are populated; the rest stay stubbed where no stable affordance exists.\n */\nexport class GenericWebChatPage implements BrowserProvider {\n readonly id: string;\n readonly origin: string;\n readonly defaultUrl: string;\n readonly defaultModel: string;\n readonly displayName: string;\n readonly composerSelector: string;\n readonly supportsMcpConnector: boolean;\n private readonly profile: WebChatProfile;\n private readonly connectorSetup?: ConnectorSetupFn;\n\n constructor(profile: WebChatProfile, connectorSetup?: ConnectorSetupFn) {\n this.profile = profile;\n this.connectorSetup = connectorSetup;\n this.id = profile.id;\n this.origin = profile.origin;\n this.defaultUrl = profile.defaultUrl;\n this.defaultModel = profile.defaultModel;\n this.displayName = profile.displayName;\n this.composerSelector = profile.selectors.composer;\n this.supportsMcpConnector = profile.supportsMcpConnector;\n }\n\n /** Throw when the composer is absent or a signed-out marker is present. */\n async assertSignedIn(page: Page): Promise<void> {\n if (this.profile.selectors.signedOut) {\n const signedOut = await page\n .locator(this.profile.selectors.signedOut)\n .count()\n .catch(() => 0);\n if (signedOut > 0) {\n throw new Error(\n `${this.displayName}: not signed in. Run \\`bridge login --provider ${this.id}\\` once.`,\n );\n }\n }\n const composer = await page\n .locator(this.composerSelector)\n .count()\n .catch(() => 0);\n if (composer === 0) {\n throw new Error(\n `${this.displayName}: composer not found — the page UI may have changed, or you are not signed in.`,\n );\n }\n }\n\n /** Type the prompt into the composer and submit it, retrying until it clears. */\n async injectPrompt(page: Page, text: string): Promise<void> {\n const composer = page.locator(this.composerSelector).first();\n for (let attempt = 0; attempt < 3; attempt += 1) {\n await composer.click();\n await composer.fill(text).catch(() => composer.type(text));\n await this.submitPrompt(page);\n if (await this.composerCleared(page)) return;\n }\n throw new Error(`${this.displayName}: composer never cleared after 3 send attempts.`);\n }\n\n /** Click the configured send button when visible, otherwise press Enter. */\n private async submitPrompt(page: Page): Promise<void> {\n const sendSelector = this.profile.selectors.send;\n if (sendSelector) {\n const clicked = await page\n .locator(sendSelector)\n .first()\n .click({ timeout: 4_000 })\n .then(() => true)\n .catch(() => false);\n if (clicked) return;\n }\n await page.keyboard.press(\"Enter\").catch(() => undefined);\n }\n\n /** Poll until the composer is empty again — the provider accepted the prompt. */\n private async composerCleared(page: Page): Promise<boolean> {\n const composer = page.locator(this.composerSelector).first();\n for (let poll = 0; poll < 10; poll += 1) {\n const text = await composer.inputValue().catch(() => composer.innerText().catch(() => \"\"));\n if (text.trim() === \"\") return true;\n await page.waitForTimeout(400).catch(() => undefined);\n }\n return false;\n }\n\n /** Wait for a new assistant message to appear, then for its text to stop growing. */\n async waitForResponse(page: Page, options?: number | ResponseWaitOptions): Promise<void> {\n const opts = typeof options === \"number\" ? { timeout: options } : (options ?? {});\n const timeout = opts.timeout ?? DEFAULT_ASK_TIMEOUT_SECONDS * 1000;\n const before = opts.previousAssistantCount ?? 0;\n await page\n .waitForFunction(\n (args) => document.querySelectorAll(args.sel).length > args.prev,\n { sel: this.profile.selectors.assistant, prev: before },\n { timeout },\n )\n .catch(() => undefined);\n await this.waitForStreamIdle(page, Math.min(timeout, 30_000));\n }\n\n /** Poll the last assistant message until its text is stable across two reads. */\n private async waitForStreamIdle(page: Page, budgetMs: number): Promise<void> {\n const deadline = Date.now() + budgetMs;\n let previous = \"\";\n while (Date.now() < deadline) {\n const current = await this.captureLastResponse(page).catch(() => \"\");\n if (current && current === previous) return;\n previous = current;\n await page.waitForTimeout(400).catch(() => undefined);\n }\n }\n\n /** Read the text of the latest assistant message. */\n async captureLastResponse(page: Page): Promise<string> {\n const last = page.locator(this.profile.selectors.assistant).last();\n return (await last.innerText().catch(() => \"\")).trim();\n }\n\n /** Count rendered assistant messages. */\n async countAssistantResponses(page: Page): Promise<number> {\n return page\n .locator(this.profile.selectors.assistant)\n .count()\n .catch(() => 0);\n }\n\n /** Capture the transcript as role-tagged messages (assistant, plus user when known). */\n async captureAllMessages(page: Page): Promise<Array<{ role: string; content: string }>> {\n const assistant = await page\n .locator(this.profile.selectors.assistant)\n .allInnerTexts()\n .catch(() => [] as string[]);\n const messages = assistant.map((content) => ({ role: \"assistant\", content: content.trim() }));\n if (!this.profile.selectors.user) return messages;\n const user = await page\n .locator(this.profile.selectors.user)\n .allInnerTexts()\n .catch(() => [] as string[]);\n return [...user.map((content) => ({ role: \"user\", content: content.trim() })), ...messages];\n }\n\n /** List history conversations from the sidebar via the configured `sidebarItem` selector. */\n async readSidebarConversations(\n page: Page,\n ): Promise<Array<{ id: string; title: string; url: string }>> {\n const selector = this.profile.selectors.sidebarItem;\n if (!selector) return [];\n const links = page.locator(selector);\n const total = Math.min(await links.count().catch(() => 0), 40);\n const base = `https://${this.origin}`;\n const conversations: Array<{ id: string; title: string; url: string }> = [];\n for (let index = 0; index < total; index += 1) {\n const link = links.nth(index);\n const href = await link.getAttribute(\"href\").catch(() => null);\n if (!href) continue;\n const url = new URL(href, base).toString();\n const title = firstLine(await link.innerText().catch(() => \"\"));\n const id = href.split(\"/\").filter(Boolean).pop() ?? href;\n conversations.push({ id, title: title || id, url });\n }\n return conversations;\n }\n\n /** Open a conversation by URL. */\n async navigateToConversation(page: Page, url: string): Promise<void> {\n await page.goto(url, { waitUntil: \"domcontentloaded\" });\n }\n\n /** Start a new conversation via the `newChat` control, or by navigating home. */\n async newConversation(page: Page): Promise<void> {\n const selector = this.profile.selectors.newChat;\n if (selector) {\n const clicked = await page\n .locator(selector)\n .first()\n .click({ timeout: 4_000 })\n .then(() => true)\n .catch(() => false);\n if (clicked) {\n await page.waitForTimeout(400).catch(() => undefined);\n return;\n }\n }\n await page.goto(this.defaultUrl, { waitUntil: \"domcontentloaded\" });\n }\n\n /** Read the current model from the picker trigger's label, else the configured default. */\n async detectCurrentModel(page: Page): Promise<string> {\n const selector = this.profile.selectors.modelTrigger;\n if (!selector) return this.defaultModel;\n const raw = await page\n .locator(selector)\n .first()\n .innerText()\n .catch(() => \"\");\n const label = firstLine(raw);\n return label && this.isLikelyModelLabel(label) ? label : this.defaultModel;\n }\n\n /** List the models offered by the picker (best-effort; opens then closes the menu). */\n async listAvailableModels(page: Page): Promise<ModelOption[]> {\n const optionSelector = this.profile.selectors.modelOption;\n if (!optionSelector || !(await this.openModelPicker(page))) return [];\n const options = page.locator(optionSelector);\n const total = Math.min(await options.count().catch(() => 0), 30);\n const models: ModelOption[] = [];\n for (let index = 0; index < total; index += 1) {\n const option = options.nth(index);\n const label = firstLine(await option.innerText().catch(() => \"\"));\n if (!label) continue;\n const checked = await option.getAttribute(\"aria-checked\").catch(() => null);\n const selected = await option.getAttribute(\"aria-selected\").catch(() => null);\n models.push({ id: label, label, selected: checked === \"true\" || selected === \"true\" });\n }\n await page.keyboard.press(\"Escape\").catch(() => undefined);\n return models;\n }\n\n /** Switch model by clicking the picker option whose label contains `query`. */\n async selectModel(page: Page, query: string): Promise<string> {\n const optionSelector = this.profile.selectors.modelOption;\n if (!optionSelector || !(await this.openModelPicker(page))) return this.defaultModel;\n const target = page.locator(optionSelector).filter({ hasText: query }).first();\n const clicked = await target\n .click({ timeout: 4_000 })\n .then(() => true)\n .catch(() => false);\n if (!clicked) {\n await page.keyboard.press(\"Escape\").catch(() => undefined);\n throw new Error(`${this.displayName}: no model matching \"${query}\".`);\n }\n await page.waitForTimeout(600).catch(() => undefined);\n return this.detectCurrentModel(page);\n }\n\n /** Open the model picker via `modelTrigger`; returns false when unavailable. */\n private async openModelPicker(page: Page): Promise<boolean> {\n const trigger = this.profile.selectors.modelTrigger;\n if (!trigger) return false;\n const opened = await page\n .locator(trigger)\n .first()\n .click({ timeout: 5_000 })\n .then(() => true)\n .catch(() => false);\n if (opened) await page.waitForTimeout(500).catch(() => undefined);\n return opened;\n }\n\n /** Prompt rewind is not supported generically. */\n async rewindLastUserPrompt(): Promise<void> {\n throw new Error(`${this.displayName}: rewinding the last prompt is not supported.`);\n }\n\n /** Click the stop-generating control if the profile defines one. */\n async stopGenerating(page: Page, timeout = 5_000): Promise<boolean> {\n if (!this.profile.selectors.stop) return false;\n const stop = page.locator(this.profile.selectors.stop).first();\n const visible = await stop.isVisible({ timeout }).catch(() => false);\n if (!visible) return false;\n await stop.click({ timeout }).catch(() => undefined);\n return true;\n }\n\n /** Attach local files by setting them on the provider's file input (`attach` selector). */\n async attachFilesToPrompt(page: Page, paths: string[]): Promise<void> {\n const selector = this.profile.selectors.attach;\n if (!selector) throw new Error(`${this.displayName}: attaching files is not supported.`);\n await page.locator(selector).first().setInputFiles(paths);\n }\n\n /** Delegate MCP connector setup to the injected provider-specific flow, if any. */\n async setupMcpConnector(\n page: Page,\n url: string,\n options?: ConnectorSetupOptions,\n ): Promise<ConnectorSetupResult> {\n if (!this.connectorSetup) {\n return {\n connectorUrl: url,\n completed: false,\n steps: [],\n warnings: [`${this.displayName} has no MCP connector setup wired.`],\n };\n }\n return this.connectorSetup(page, url, options);\n }\n\n /** Heuristic: a short label containing a known model keyword. */\n isLikelyModelLabel(value: string): boolean {\n const trimmed = value.trim().toLowerCase();\n if (!trimmed || trimmed.length > 40) return false;\n return MODEL_KEYWORDS.some((keyword) => trimmed.includes(keyword));\n }\n}\n","/** Raised when a requested provider id/alias is not in the registry. */\nexport class UnknownProviderError extends Error {\n constructor(value: string, valid: readonly string[]) {\n super(`Unknown provider \"${value}\". Valid providers: ${valid.join(\", \")}.`);\n this.name = \"UnknownProviderError\";\n }\n}\n","import {\n type BridgeProviderId,\n DEFAULT_PROVIDER,\n PROVIDER_ALIASES,\n PROVIDER_CONFIG,\n PROVIDER_IDS,\n} from \"@/config\";\nimport type { BrowserProvider } from \"./browserProviderTypes.ts\";\nimport { CHATGPT_PROVIDER } from \"./chatgptProviderConfig.ts\";\nimport { setupMcpConnectorInClaude } from \"./claude/claudeConnector.ts\";\nimport { GEMINI_PROVIDER } from \"./geminiProviderConfig.ts\";\nimport { type ConnectorSetupFn, GenericWebChatPage } from \"./genericWebChatPage.ts\";\nimport { UnknownProviderError } from \"./unknownProviderError.ts\";\n\n/** Build a generic selector-driven adapter, optionally with a bespoke connector flow. */\nfunction genericProvider(id: BridgeProviderId, connectorSetup?: ConnectorSetupFn): BrowserProvider {\n return new GenericWebChatPage({ id, ...PROVIDER_CONFIG[id] }, connectorSetup);\n}\n\n/**\n * Browser adapters keyed by id. Metadata + selectors come from `@/config` (the SSOT);\n * this binds each id to behavior — a bespoke `*Page` class for ChatGPT/Gemini, the\n * generic adapter otherwise. The `Record<BridgeProviderId, …>` annotation makes a\n * missing adapter a compile error.\n */\nexport const PROVIDERS: Record<BridgeProviderId, BrowserProvider> = {\n chatgpt: CHATGPT_PROVIDER,\n gemini: GEMINI_PROVIDER,\n claude: genericProvider(\"claude\", setupMcpConnectorInClaude),\n deepseek: genericProvider(\"deepseek\"),\n grok: genericProvider(\"grok\"),\n perplexity: genericProvider(\"perplexity\"),\n};\n\nfunction unwrapProvider(input: unknown): string | undefined {\n if (typeof input === \"string\") return input;\n if (input && typeof input === \"object\") {\n const record = input as { value?: unknown; id?: unknown };\n const raw = record.value ?? record.id;\n if (typeof raw === \"string\") return raw;\n }\n return undefined;\n}\n\n/**\n * Normalize a CLI/config provider string to a supported id.\n * Empty or absent → the default provider; an explicit unknown value throws\n * {@link UnknownProviderError} listing the valid ids (never silently coerced).\n */\nexport function normalizeProvider(\n input: string | { value?: string } | { id?: string } | undefined,\n): BridgeProviderId {\n const value = unwrapProvider(input)?.trim().toLowerCase();\n if (!value) return DEFAULT_PROVIDER;\n const resolved = PROVIDER_ALIASES[value] ?? value;\n if (resolved in PROVIDER_CONFIG) return resolved as BridgeProviderId;\n throw new UnknownProviderError(value, PROVIDER_IDS);\n}\n\n/** Resolve the browser adapter for a provider id/alias. */\nexport function getBrowserProvider(input: string | { id?: string } | undefined): BrowserProvider {\n return PROVIDERS[normalizeProvider(input)];\n}\n\n/**\n * Parse a `--provider` value into a deduped id list. Accepts a comma-separated list\n * (`claude,deepseek,grok`) for fan-out; empty/absent → the default provider. Each part\n * is normalized, so an unknown provider throws {@link UnknownProviderError}.\n */\nexport function parseProviderList(spec: string | undefined): BridgeProviderId[] {\n if (!spec?.trim()) return [DEFAULT_PROVIDER];\n const ids = spec.split(\",\").map((part) => normalizeProvider(part));\n return [...new Set(ids)];\n}\n\nexport { DEFAULT_PROVIDER, PROVIDER_IDS };\nexport type { BridgeProviderId };\nexport type { BrowserProvider, ResponseWaitOptions } from \"./browserProviderTypes.ts\";\nexport { UnknownProviderError } from \"./unknownProviderError.ts\";\n","/**\n * Effect Schema definitions for the providers feature.\n *\n * These schemas are the single source of truth for runtime validation of\n * provider-related input types at boundaries. The existing implementation\n * classes (`ChatGptPage`, `GenericWebChatPage`, `BrowserManager`, etc.) remain\n * untouched; these schemas enable gradual adoption of Effect-based validation.\n *\n * @module\n */\nimport { Schema } from \"effect\";\n\n// ---------------------------------------------------------------------------\n// Provider id schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for a supported provider id literal.\n */\nexport const BridgeProviderIdSchema = Schema.Literal(\n \"chatgpt\",\n \"gemini\",\n \"claude\",\n \"deepseek\",\n \"grok\",\n \"perplexity\",\n);\n\n/**\n * BridgeProviderId type derived from the schema.\n */\nexport type BridgeProviderIdFromSchema = Schema.Schema.Type<typeof BridgeProviderIdSchema>;\n\n// ---------------------------------------------------------------------------\n// ResponseWaitOptions schema\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the options passed when waiting on an assistant response in the browser.\n */\nexport const ResponseWaitOptionsSchema = Schema.Struct({\n timeout: Schema.optional(Schema.Number),\n previousAssistantCount: Schema.optional(Schema.Number),\n previousLastAssistantText: Schema.optional(Schema.String),\n expectImages: Schema.optional(Schema.Number),\n});\n\n/**\n * ResponseWaitOptions type derived from the schema.\n */\nexport type ResponseWaitOptionsFromSchema = Schema.Schema.Type<typeof ResponseWaitOptionsSchema>;\n\n// ---------------------------------------------------------------------------\n// ConnectorSetupOptions schema\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for options passed to the MCP connector setup UI.\n */\nexport const ConnectorSetupOptionsSchema = Schema.Struct({\n connectorName: Schema.optional(Schema.String),\n automatic: Schema.optional(Schema.Boolean),\n});\n\n/**\n * ConnectorSetupOptions type derived from the schema.\n */\nexport type ConnectorSetupOptionsFromSchema = Schema.Schema.Type<\n typeof ConnectorSetupOptionsSchema\n>;\n\n// ---------------------------------------------------------------------------\n// ConnectorSetupResult schema\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the outcome of an MCP connector setup flow.\n */\nexport const ConnectorSetupResultSchema = Schema.Struct({\n connectorUrl: Schema.String,\n completed: Schema.Boolean,\n steps: Schema.Array(Schema.String),\n warnings: Schema.Array(Schema.String),\n});\n\n/**\n * ConnectorSetupResult type derived from the schema.\n */\nexport type ConnectorSetupResultFromSchema = Schema.Schema.Type<typeof ConnectorSetupResultSchema>;\n\n// ---------------------------------------------------------------------------\n// ModelOption schema\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for a model picker option from the provider UI.\n */\nexport const ModelOptionSchema = Schema.Struct({\n id: Schema.String,\n label: Schema.String,\n selected: Schema.Boolean,\n});\n\n/**\n * ModelOption type derived from the schema.\n */\nexport type ModelOptionFromSchema = Schema.Schema.Type<typeof ModelOptionSchema>;\n\n// ---------------------------------------------------------------------------\n// ProviderSelectors schema\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for DOM selectors describing a web-chat provider's core surface.\n */\nexport const ProviderSelectorsSchema = Schema.Struct({\n composer: Schema.String,\n assistant: Schema.String,\n user: Schema.optional(Schema.String),\n stop: Schema.optional(Schema.String),\n send: Schema.optional(Schema.String),\n newChat: Schema.optional(Schema.String),\n sidebarItem: Schema.optional(Schema.String),\n modelTrigger: Schema.optional(Schema.String),\n modelOption: Schema.optional(Schema.String),\n attach: Schema.optional(Schema.String),\n signedOut: Schema.optional(Schema.String),\n});\n\n/**\n * ProviderSelectors type derived from the schema.\n */\nexport type ProviderSelectorsFromSchema = Schema.Schema.Type<typeof ProviderSelectorsSchema>;\n\n// ---------------------------------------------------------------------------\n// ProviderConfigEntry schema\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the static metadata + core selectors for a supported browser provider.\n */\nexport const ProviderConfigEntrySchema = Schema.Struct({\n displayName: Schema.String,\n supportsMcpConnector: Schema.Boolean,\n origin: Schema.String,\n defaultUrl: Schema.String,\n defaultModel: Schema.String,\n selectors: ProviderSelectorsSchema,\n});\n\n/**\n * ProviderConfigEntry type derived from the schema.\n */\nexport type ProviderConfigEntryFromSchema = Schema.Schema.Type<typeof ProviderConfigEntrySchema>;\n","import type { FanoutResult } from \"@/features/bridge\";\nimport { parseProviderList } from \"@/features/providers\";\nimport { McpServer as McpProtocolServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\n/**\n * The outbound MCP surface: a local agent connects to this server and calls `ask` to\n * drive one or more web chats. This is the OPPOSITE direction to the inbound MCP server\n * in `tools/` (which exposes repo tools TO the web model). Both go over the same\n * fan-out core, injected here as `runFanout`.\n */\nexport interface AskGatewayDeps {\n /** Run one prompt across the resolved providers and return the keyed result. */\n runFanout: (\n providers: string[],\n prompt: string,\n opts: { timeoutMs?: number },\n ) => Promise<FanoutResult>;\n}\n\n/** Zod raw shape for the `ask` tool parameters. */\nexport const ASK_TOOL_PARAMS = {\n prompt: z.string().min(1).describe(\"The prompt to send to each provider.\"),\n providers: z\n .string()\n .optional()\n .describe(\"Comma-separated provider ids (e.g. 'chatgpt,gemini'); omit for the default.\"),\n timeoutSeconds: z.number().positive().optional().describe(\"Per-provider timeout in seconds.\"),\n};\n\n/** Arguments accepted by {@link handleAskGatewayCall}. */\nexport interface AskGatewayArgs {\n prompt: string;\n providers?: string;\n timeoutSeconds?: number;\n}\n\n/**\n * Handle one `ask` call: resolve the provider list (fail-loud on unknown), fan the\n * prompt out over the core, and return the keyed result as JSON. Never throws — an\n * unknown provider becomes `{ ok: false }` so the tool reports it cleanly.\n */\nexport async function handleAskGatewayCall(\n deps: AskGatewayDeps,\n args: AskGatewayArgs,\n): Promise<{ ok: boolean; output: string }> {\n let providers: string[];\n try {\n providers = parseProviderList(args.providers);\n } catch (err) {\n return { ok: false, output: err instanceof Error ? err.message : String(err) };\n }\n const result = await deps.runFanout(providers, args.prompt, {\n timeoutMs: args.timeoutSeconds ? args.timeoutSeconds * 1000 : undefined,\n });\n return { ok: true, output: JSON.stringify(result) };\n}\n\n/**\n * Build an MCP server exposing a single `ask` tool over the fan-out core. Served over\n * stdio by {@link serveAskGatewayStdio}; the browser-backed `runFanout` is injected at\n * the composition root — `bridge serve` (`runServe` in the terminal feature).\n */\nexport function createAskGatewayServer(deps: AskGatewayDeps): McpProtocolServer {\n const mcp = new McpProtocolServer({ name: \"ai-browser-bridge-ask\", version: \"0.1.0\" });\n mcp.tool(\n \"ask\",\n \"Ask one prompt across one or more web-chat providers and return each reply, keyed by provider.\",\n ASK_TOOL_PARAMS,\n {},\n async (args: Record<string, unknown>) => {\n // Args are validated against ASK_TOOL_PARAMS by the SDK before this runs.\n const result = await handleAskGatewayCall(deps, args as unknown as AskGatewayArgs);\n return { content: [{ type: \"text\" as const, text: result.output }], isError: !result.ok };\n },\n );\n return mcp;\n}\n","import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { type AskGatewayDeps, createAskGatewayServer } from \"./askGatewayServer.ts\";\n\n/**\n * Serve the outbound `ask` MCP gateway over stdio and block until the transport\n * closes (the client disconnects, or the process is signalled).\n *\n * This is the composition-root entry the `ask` server was designed for: a local\n * agent (Claude Code, Cursor, …) spawns `bridge serve`, speaks MCP over stdio, and\n * calls the `ask` tool to drive one or more web chats. The browser-backed\n * `runFanout` is injected via {@link AskGatewayDeps}, so this stays transport-only.\n *\n * stdout is the JSON-RPC channel — the caller MUST redirect logs to stderr before\n * invoking this, or any stray stdout line corrupts the protocol stream.\n */\nexport async function serveAskGatewayStdio(deps: AskGatewayDeps): Promise<void> {\n const server = createAskGatewayServer(deps);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n await new Promise<void>((resolve) => {\n // `connect` installs the SDK's own onclose; chain ours so cleanup still runs.\n const priorOnClose = transport.onclose;\n transport.onclose = () => {\n priorOnClose?.();\n resolve();\n };\n });\n}\n","/**\n * Effect Schema definitions for the agentGateway feature.\n *\n * These schemas mirror the Zod `ASK_TOOL_PARAMS` shape used by the MCP SDK\n * boundary in `askGatewayServer.ts` and are intended for internal validation,\n * type derivation, and any future Effect-native tool handling.\n *\n * @module\n */\nimport { Schema } from \"effect\";\n\n// ---------------------------------------------------------------------------\n// ask tool arguments\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the `ask` tool parameters exposed over the outbound MCP gateway.\n */\nexport const AskToolArgsSchema = Schema.Struct({\n prompt: Schema.String.pipe(Schema.minLength(1)).annotations({\n description: \"The prompt to send to each provider.\",\n }),\n providers: Schema.optional(\n Schema.String.annotations({\n description: \"Comma-separated provider ids (e.g. 'chatgpt,gemini'); omit for the default.\",\n }),\n ),\n timeoutSeconds: Schema.optional(\n Schema.Number.pipe(Schema.positive()).annotations({\n description: \"Per-provider timeout in seconds.\",\n }),\n ),\n});\n\n/**\n * Ask tool arguments type derived from the schema.\n */\nexport type AskToolArgs = Schema.Schema.Type<typeof AskToolArgsSchema>;\n\n// ---------------------------------------------------------------------------\n// ask tool result\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the result returned by {@link handleAskGatewayCall}.\n */\nexport const AskToolResultSchema = Schema.Struct({\n ok: Schema.Boolean,\n output: Schema.String,\n});\n\n/**\n * Ask tool result type derived from the schema.\n */\nexport type AskToolResult = Schema.Schema.Type<typeof AskToolResultSchema>;\n","import { execFile } from \"node:child_process\";\nimport { DEFAULT_MCP_PORT, DEFAULT_PERMISSION_MODE } from \"@/config\";\nimport { type ModelProfile, UNKNOWN_MODEL_PROFILE, findModelProfile } from \"@/features/domain\";\nimport { type PermissionMode, normalizePermissionMode } from \"@/features/domain\";\nimport type { BridgeConfig, Message } from \"@/features/domain\";\nimport { BrowserManager } from \"@/features/providers\";\nimport { getBrowserProvider, normalizeProvider } from \"@/features/providers\";\nimport { resolveFileMentions } from \"@/features/store\";\nimport { appendBridgeLog } from \"@/features/store\";\nimport { ensureBridgeDir, sessionsDir } from \"@/features/store\";\nimport { appendSessionEvent, createSession, updateSession } from \"@/features/store\";\nimport { type McpServerHandle, type McpToolAction, startMcpServer } from \"@/features/tools\";\nimport { CloudflareTunnelClass } from \"@/features/tunnel\";\nimport { runHooks } from \"@/features/user-config\";\nimport { loadHooksConfig } from \"@/features/user-config\";\nimport type {\n AskEngineInput,\n BuildEngineContext,\n EngineRuntimeState,\n ShutdownEngineInput,\n StartEngineOptions,\n} from \"../bridgeEngineTypes.ts\";\nimport { loadConfig, saveConfig } from \"../loadConfig.ts\";\nimport { Orchestrator } from \"./orchestrator.ts\";\n\n/** Build `<tunnelUrl>/mcp`, the URL ChatGPT's connector points at. */\nexport function mcpConnectorUrl(tunnelUrl: string): string {\n return `${tunnelUrl.replace(/\\/+$/, \"\")}/mcp`;\n}\n\n/** Rough character-to-token ratio for estimation. */\nconst DEFAULT_CHARS_PER_TOKEN = 4;\nconst ANTHROPIC_CHARS_PER_TOKEN = 3.5;\nconst MESSAGE_OVERHEAD_TOKENS = 4;\n\n/** Estimate token count for a single string. */\nexport function estimateTokens(text: string, charsPerToken = DEFAULT_CHARS_PER_TOKEN): number {\n if (text.length === 0) return 0;\n return Math.ceil(text.length / charsPerToken);\n}\n\n/** Running context counter that tracks usage against a limit. */\nclass ContextCounter {\n private total = 0;\n private profile: ModelProfile;\n\n constructor(\n private limit: number,\n modelName?: string,\n ) {\n this.profile = modelName ? findModelProfile(modelName) : UNKNOWN_MODEL_PROFILE;\n if (modelName) this.limit = this.profile.contextWindow;\n }\n\n get contextLimit(): number {\n return this.limit;\n }\n\n get modelLabel(): string {\n return this.profile.label;\n }\n\n get modelProfile(): ModelProfile {\n return this.profile;\n }\n\n add(message: Message): void {\n this.total += MESSAGE_OVERHEAD_TOKENS + this.estimateForProvider(message.content);\n for (const tc of message.toolCalls ?? []) {\n this.total +=\n MESSAGE_OVERHEAD_TOKENS + this.estimateForProvider(JSON.stringify(tc.arguments));\n }\n }\n\n get count(): number {\n return this.total;\n }\n\n get fraction(): number {\n return this.total / this.limit;\n }\n\n get summary(): string {\n const pct = (this.fraction * 100).toFixed(1);\n return `~${this.total.toLocaleString()} / ${this.limit.toLocaleString()} (${pct}%)`;\n }\n\n get isNearLimit(): boolean {\n return this.fraction > 0.8;\n }\n\n reset(): void {\n this.total = 0;\n }\n\n setLimit(limit: number): void {\n this.limit = limit;\n }\n\n setModel(modelName: string): void {\n this.profile = findModelProfile(modelName);\n this.limit = this.profile.contextWindow;\n }\n\n private estimateForProvider(text: string): number {\n const charsPerToken =\n this.profile.provider === \"anthropic\" ? ANTHROPIC_CHARS_PER_TOKEN : DEFAULT_CHARS_PER_TOKEN;\n return estimateTokens(text, charsPerToken);\n }\n}\n\n/** Default MCP server port when none is configured. */\n\n/** Resolve the repo's current git branch, or undefined when not a git repo. */\nfunction currentGitBranch(repoPath: string): Promise<string | undefined> {\n return new Promise((resolve) => {\n execFile(\"git\", [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], { cwd: repoPath }, (error, stdout) => {\n resolve(error ? undefined : stdout.trim() || undefined);\n });\n });\n}\n\nfunction defaultEngineLog(line: string): void {\n process.stderr.write(`${line}\\n`);\n}\n\nfunction resolveEngineLog(options: StartEngineOptions): (line: string) => void {\n return options.log ?? defaultEngineLog;\n}\n\nfunction logHookWarnings(errors: string[], log: (line: string) => void): void {\n for (const error of errors) log(`Hooks warning: ${error}`);\n}\n\n/** Load, normalise, and persist the effective config for this run. */\nasync function resolveEngineConfig(options: StartEngineOptions): Promise<BridgeConfig> {\n const repoPath = options.repoPath ?? process.cwd();\n await ensureBridgeDir(repoPath);\n const saved = await loadConfig(repoPath);\n const config = await loadConfig(repoPath, {\n provider: options.provider ?? saved.provider ?? \"chatgpt\",\n mcpPort: options.mcpPort ?? saved.mcpPort ?? DEFAULT_MCP_PORT,\n tunnelUrl: undefined,\n });\n config.provider = normalizeProvider(config.provider);\n config.permissionMode = normalizePermissionMode(config.permissionMode ?? DEFAULT_PERMISSION_MODE);\n await saveConfig(config);\n return config;\n}\n\ninterface EngineFeatureFlags {\n withTools: boolean;\n withTunnel: boolean;\n withBrowser: boolean | undefined;\n}\n\nfunction resolveEngineFlags(\n options: StartEngineOptions,\n supportsMcpConnector: boolean,\n): EngineFeatureFlags {\n const withTools = (options.withTools ?? true) && supportsMcpConnector;\n const withTunnel = (options.withTunnel ?? withTools) && supportsMcpConnector;\n return { withTools, withTunnel, withBrowser: options.withBrowser };\n}\n\nasync function initEngineRuntime(\n config: BridgeConfig,\n hooksConfig: Awaited<ReturnType<typeof loadHooksConfig>>,\n): Promise<EngineRuntimeState & { branch?: string }> {\n const sessionStore = { baseDir: sessionsDir(config.repoPath) };\n const branch = await currentGitBranch(config.repoPath);\n const session = await createSession(\n {\n repoPath: config.repoPath,\n model: config.model ?? null,\n contextLimit: config.contextLimit,\n tunnelUrl: config.tunnelUrl ?? null,\n },\n sessionStore,\n );\n await runHooks(\"SessionStart\", hooksConfig.hooks).catch(() => []);\n return {\n sessionId: session.metadata.id,\n permissionMode: normalizePermissionMode(config.permissionMode ?? DEFAULT_PERMISSION_MODE),\n branch,\n };\n}\n\nasync function recordToolAction(input: {\n toolActions: McpToolAction[];\n getSessionId: () => string;\n sessionStore: { baseDir: string };\n action: McpToolAction;\n}): Promise<void> {\n input.toolActions.push(input.action);\n await appendSessionEvent(\n input.getSessionId(),\n {\n type: \"action\",\n name: input.action.name,\n status: input.action.status,\n content: input.action.data?.error ? String(input.action.data.error) : undefined,\n data: input.action.data,\n },\n input.sessionStore,\n ).catch(() => {});\n}\n\nasync function maybeStartMcp(input: {\n config: BridgeConfig;\n flags: EngineFeatureFlags;\n hooksConfig: Awaited<ReturnType<typeof loadHooksConfig>>;\n runtime: EngineRuntimeState;\n toolActions: McpToolAction[];\n log: (line: string) => void;\n}): Promise<McpServerHandle | null> {\n if (!input.flags.withTools) return null;\n const sessionStore = { baseDir: sessionsDir(input.config.repoPath) };\n const getSessionId = () => input.runtime.sessionId;\n const mcpServer = await startMcpServer(input.config.repoPath, input.config.mcpPort, {\n getPermissionMode: () => input.runtime.permissionMode,\n hooks: input.hooksConfig.hooks,\n onToolAction: (action) =>\n recordToolAction({ toolActions: input.toolActions, getSessionId, sessionStore, action }),\n });\n input.log(`MCP: ${mcpServer.url}`);\n return mcpServer;\n}\n\ninterface EngineBootState {\n config: BridgeConfig;\n hooksConfig: Awaited<ReturnType<typeof loadHooksConfig>>;\n runtime: EngineRuntimeState & { branch?: string };\n flags: EngineFeatureFlags;\n toolActions: McpToolAction[];\n mcpServer: McpServerHandle | null;\n log: (line: string) => void;\n getSessionId: () => string;\n}\n\nasync function loadEngineBootState(options: StartEngineOptions): Promise<EngineBootState> {\n const log = resolveEngineLog(options);\n const config = await resolveEngineConfig(options);\n const hooksConfig = await loadHooksConfig({ repoRoot: config.repoPath });\n const flags = resolveEngineFlags(\n options,\n getBrowserProvider(config.provider).supportsMcpConnector,\n );\n logHookWarnings(hooksConfig.errors, log);\n const runtime = await initEngineRuntime(config, hooksConfig);\n const toolActions: McpToolAction[] = [];\n const mcpServer = await maybeStartMcp({ config, flags, hooksConfig, runtime, toolActions, log });\n return {\n config,\n hooksConfig,\n runtime,\n flags,\n toolActions,\n mcpServer,\n log,\n getSessionId: () => runtime.sessionId,\n };\n}\n\nfunction attachPersistenceListener(input: {\n orchestrator: Orchestrator;\n counter: ContextCounter;\n config: BridgeConfig;\n getSessionId: () => string;\n}): void {\n const sessionStore = { baseDir: sessionsDir(input.config.repoPath) };\n input.orchestrator.on((event) => {\n if (event.type === \"message\") {\n input.counter.add(event.message);\n appendBridgeLog({\n repoPath: input.config.repoPath,\n type: `chatgpt_${event.message.role}_message`,\n data: { content: event.message.content },\n }).catch(() => {});\n appendSessionEvent(\n input.getSessionId(),\n {\n type: \"message\",\n role: event.message.role,\n content: event.message.content,\n data: { messageId: event.message.id },\n },\n sessionStore,\n ).catch(() => {});\n }\n if (event.type === \"conversation_synced\") {\n input.counter.reset();\n for (const message of event.messages) input.counter.add(message);\n }\n if (event.type === \"reset\") input.counter.reset();\n if (event.type === \"model_changed\") {\n input.counter.setModel(event.model);\n input.config.model = event.model;\n input.config.contextLimit = event.contextLimit;\n saveConfig(input.config).catch(() => {});\n updateSession(\n input.getSessionId(),\n { model: event.model, contextLimit: event.contextLimit },\n sessionStore,\n ).catch(() => {});\n }\n });\n}\n\nasync function startTunnel(input: {\n config: BridgeConfig;\n sessionId: string;\n log: (line: string) => void;\n}): Promise<{ tunnel: CloudflareTunnelClass | null; connectorUrl: string }> {\n try {\n const tunnel = new CloudflareTunnelClass();\n const tunnelUrl = await tunnel.start(input.config.mcpPort);\n input.config.tunnelUrl = tunnelUrl;\n const connectorUrl = mcpConnectorUrl(tunnelUrl);\n await updateSession(\n input.sessionId,\n { tunnelUrl },\n { baseDir: sessionsDir(input.config.repoPath) },\n ).catch(() => {});\n input.log(`Tunnel: ${tunnelUrl}`);\n input.log(`Connector: ${connectorUrl}`);\n return { tunnel, connectorUrl };\n } catch {\n input.log(\n \"Tunnel: failed to start (cloudflared not installed?). MCP tools require a public URL ChatGPT can reach.\",\n );\n return { tunnel: null, connectorUrl: \"\" };\n }\n}\n\nasync function connectBrowser(input: {\n orchestrator: Orchestrator;\n connectorUrl: string;\n config: BridgeConfig;\n log: (line: string) => void;\n}): Promise<BrowserManager | null> {\n const providerId = normalizeProvider(input.config.provider);\n let browser: BrowserManager | null = new BrowserManager(input.config.repoPath, providerId);\n try {\n const provider = getBrowserProvider(providerId);\n const page = await browser.launch();\n input.orchestrator.setPage(page);\n if (browser.attachedViaCdp.value) {\n input.log(\"Browser: attached to Chrome on debug port (reusing your session).\");\n } else if (browser.spawnedNew.value) {\n input.log(`Browser: started isolated ${provider.displayName} profile.`);\n } else {\n input.log(\"Browser: connected.\");\n }\n if (input.connectorUrl && provider.supportsMcpConnector) {\n const result = await input.orchestrator.openConnectorSetup({\n connectorUrl: input.connectorUrl,\n automatic: true,\n });\n input.log(`Connector setup: ${result.completed ? \"ready\" : \"needs attention\"}`);\n } else if (!provider.supportsMcpConnector) {\n input.log(\n `Provider: ${provider.displayName} web has no MCP connector — @file mentions only.`,\n );\n }\n } catch (err) {\n browser = null;\n input.log(`Browser: failed to connect (${err instanceof Error ? err.message : String(err)}).`);\n }\n await input.orchestrator.start().catch(() => {});\n return browser;\n}\n\nasync function bootEngine(options: StartEngineOptions): Promise<BuildEngineContext> {\n const boot = await loadEngineBootState(options);\n const orchestrator = new Orchestrator(boot.config);\n const counter = new ContextCounter(boot.config.contextLimit, boot.config.model);\n attachPersistenceListener({\n orchestrator,\n counter,\n config: boot.config,\n getSessionId: boot.getSessionId,\n });\n const tunnel = boot.flags.withTunnel\n ? await startTunnel({ config: boot.config, sessionId: boot.runtime.sessionId, log: boot.log })\n : { tunnel: null, connectorUrl: \"\" };\n const browser =\n boot.flags.withBrowser === false\n ? null\n : await connectBrowser({\n orchestrator,\n connectorUrl: tunnel.connectorUrl,\n config: boot.config,\n log: boot.log,\n });\n return {\n config: boot.config,\n orchestrator,\n counter,\n browser,\n mcpServer: boot.mcpServer,\n tunnel: tunnel.tunnel,\n connectorUrl: tunnel.connectorUrl,\n hooksConfig: boot.hooksConfig,\n toolActions: boot.toolActions,\n branch: boot.runtime.branch,\n runtime: { sessionId: boot.runtime.sessionId, permissionMode: boot.runtime.permissionMode },\n };\n}\n\n/** Fully wired bridge runtime: browser, MCP, orchestrator, and session. */\nexport class BridgeEngine {\n readonly config: BridgeConfig;\n readonly counter: ContextCounter;\n readonly browser: BrowserManager | null;\n readonly connectorUrl: string;\n readonly hooksConfig: BuildEngineContext[\"hooksConfig\"];\n readonly toolActions: McpToolAction[];\n readonly branch?: string;\n\n private readonly orchestrator: Orchestrator;\n private readonly mcpServer: McpServerHandle | null;\n private readonly tunnel: CloudflareTunnelClass | null;\n private runtime: EngineRuntimeState;\n\n private constructor(private readonly ctx: BuildEngineContext) {\n this.config = ctx.config;\n this.orchestrator = ctx.orchestrator;\n this.counter = ctx.counter;\n this.browser = ctx.browser;\n this.mcpServer = ctx.mcpServer;\n this.tunnel = ctx.tunnel;\n this.connectorUrl = ctx.connectorUrl;\n this.hooksConfig = ctx.hooksConfig;\n this.toolActions = ctx.toolActions;\n this.branch = ctx.branch;\n this.runtime = { ...ctx.runtime };\n }\n\n /** Wire up and start a bridge engine. */\n static async start(options: StartEngineOptions = {}): Promise<BridgeEngine> {\n return new BridgeEngine(await bootEngine(options));\n }\n\n /** Browser automation coordinator. */\n getOrchestrator(): Orchestrator {\n return this.orchestrator;\n }\n\n /** Resolve file mentions, run hooks, and send the prompt. */\n async ask(input: AskEngineInput): Promise<Message | null> {\n await runHooks(\"UserPromptSubmit\", this.hooksConfig.hooks).catch(() => []);\n const resolved = await resolveFileMentions(input.content, this.config.repoPath);\n return this.orchestrator.sendPrompt({\n content: resolved.prompt,\n timeoutMs: input.timeoutMs,\n expectImages: input.expectImages,\n });\n }\n\n /** Run SessionEnd hooks and stop tunnel, MCP server, and optionally Chrome. */\n async shutdown(input: ShutdownEngineInput = {}): Promise<void> {\n await this.orchestrator.stopResponse().catch(() => {});\n await runHooks(\"SessionEnd\", this.hooksConfig.hooks).catch(() => []);\n this.tunnel?.stop();\n this.mcpServer?.close();\n if (input.closeBrowser) await this.browser?.close().catch(() => {});\n }\n\n get sessionId(): string {\n return this.runtime.sessionId;\n }\n\n set sessionId(id: string) {\n this.runtime.sessionId = id;\n this.ctx.runtime.sessionId = id;\n }\n\n get permissionMode(): PermissionMode {\n return this.runtime.permissionMode;\n }\n\n set permissionMode(mode: PermissionMode) {\n this.runtime.permissionMode = normalizePermissionMode(mode);\n this.ctx.runtime.permissionMode = this.runtime.permissionMode;\n this.config.permissionMode = this.runtime.permissionMode;\n saveConfig(this.config).catch(() => {});\n }\n}\n\nexport type {\n AskEngineInput,\n ShutdownEngineInput,\n StartEngineOptions,\n} from \"../bridgeEngineTypes.ts\";\nexport { ContextCounter };\n","import { type ChildProcess, spawn } from \"node:child_process\";\nimport { Context, Effect, Layer } from \"effect\";\nimport { CloudflareTunnelError } from \"./tunnelSchemas.ts\";\n\n/**\n * Service interface for the Cloudflare Tunnel subprocess manager.\n */\nexport interface CloudflareTunnelService {\n /**\n * Start the tunnel, returning the public HTTPS URL.\n *\n * @param localPort - The local port to expose.\n * @returns The public tunnel URL.\n */\n readonly start: (localPort: number) => Effect.Effect<string, CloudflareTunnelError>;\n\n /**\n * Get the current public URL (empty string if not started).\n *\n * @returns The current public URL.\n */\n readonly getUrl: () => Effect.Effect<string>;\n\n /**\n * Stop the tunnel subprocess.\n *\n * @returns void\n */\n readonly stop: () => Effect.Effect<void>;\n}\n\n/** Context Tag for the Cloudflare Tunnel service. */\nexport class CloudflareTunnel extends Context.Tag(\"CloudflareTunnel\")<\n CloudflareTunnel,\n CloudflareTunnelService\n>() {}\n\n/** Spawn cloudflared for a local HTTP port. */\nfunction spawnCloudflared(localPort: number): ChildProcess {\n return spawn(\"cloudflared\", [\"tunnel\", \"--url\", `http://localhost:${localPort}`], {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n}\n\n/** Attach stdout/stderr listeners that extract the tunnel URL from cloudflared output. */\nfunction attachTunnelOutput(input: {\n proc: ChildProcess;\n state: { publicUrl: string; settled: boolean };\n settle: (result: { url?: string; error?: Error }) => void;\n clear: () => void;\n}): void {\n const onLine = (line: string) => {\n const match = line.match(/https:\\/\\/[a-z0-9-]+\\.trycloudflare\\.com/);\n if (!match) return;\n input.state.publicUrl = match[0];\n input.clear();\n input.settle({ url: match[0] });\n };\n input.proc.stdout?.on(\"data\", (chunk: Buffer) => {\n for (const line of chunk.toString().split(\"\\n\")) onLine(line);\n });\n input.proc.stderr?.on(\"data\", (chunk: Buffer) => {\n for (const line of chunk.toString().split(\"\\n\")) onLine(line);\n });\n}\n\n/** Attach process error/exit handlers for tunnel startup failures. */\nfunction attachTunnelLifecycle(input: {\n proc: ChildProcess;\n state: { publicUrl: string; settled: boolean };\n settle: (result: { url?: string; error?: Error }) => void;\n clear: () => void;\n}): void {\n input.proc.on(\"error\", (err) => {\n input.clear();\n input.settle({ error: err });\n });\n input.proc.on(\"exit\", (code) => {\n input.clear();\n if (code !== 0 && !input.state.publicUrl) {\n input.settle({ error: new Error(`cloudflared exited with code ${code}`) });\n }\n });\n}\n\n/** Wait until cloudflared prints a public trycloudflare.com URL. */\nfunction waitForTunnelUrl(proc: ChildProcess): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const state = { publicUrl: \"\", settled: false };\n const settle = (result: { url?: string; error?: Error }) => {\n if (state.settled) return;\n state.settled = true;\n if (result.error) reject(result.error);\n else resolve(result.url ?? \"\");\n };\n const timeout = setTimeout(() => {\n settle({ error: new Error(\"Timed out waiting for tunnel URL\") });\n }, 30_000);\n const clear = () => clearTimeout(timeout);\n attachTunnelOutput({ proc, state, settle, clear });\n attachTunnelLifecycle({ proc, state, settle, clear });\n });\n}\n\n/** Live implementation of the CloudflareTunnel service. */\nexport const CloudflareTunnelLive: Layer.Layer<CloudflareTunnel> = Layer.sync(\n CloudflareTunnel,\n () => {\n let proc: ChildProcess | null = null;\n let publicUrl = \"\";\n\n return {\n start: (localPort: number) =>\n Effect.tryPromise({\n try: async () => {\n proc = spawnCloudflared(localPort);\n publicUrl = await waitForTunnelUrl(proc);\n return publicUrl;\n },\n catch: (error) =>\n new CloudflareTunnelError({\n message: error instanceof Error ? error.message : String(error),\n }),\n }),\n\n getUrl: () => Effect.sync(() => publicUrl),\n\n stop: () =>\n Effect.sync(() => {\n if (proc) {\n proc.kill(\"SIGTERM\");\n proc = null;\n }\n }),\n };\n },\n);\n","import { Data } from \"effect\";\n\n/**\n * Error raised when the Cloudflare Tunnel fails to start or times out.\n *\n * @param message - Human-readable description of the failure.\n */\nexport class CloudflareTunnelError extends Data.TaggedError(\"CloudflareTunnelError\")<{\n readonly message: string;\n}> {}\n","import { type ChildProcess, spawn } from \"node:child_process\";\n\n/** Spawn cloudflared for a local HTTP port. */\nfunction spawnCloudflared(localPort: number): ChildProcess {\n return spawn(\"cloudflared\", [\"tunnel\", \"--url\", `http://localhost:${localPort}`], {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n}\n\n/** Attach stdout/stderr listeners that extract the tunnel URL from cloudflared output. */\nfunction attachTunnelOutput(input: {\n proc: ChildProcess;\n state: { publicUrl: string; settled: boolean };\n settle: (result: { url?: string; error?: Error }) => void;\n clear: () => void;\n}): void {\n const onLine = (line: string) => {\n const match = line.match(/https:\\/\\/[a-z0-9-]+\\.trycloudflare\\.com/);\n if (!match) return;\n input.state.publicUrl = match[0];\n input.clear();\n input.settle({ url: match[0] });\n };\n input.proc.stdout?.on(\"data\", (chunk: Buffer) => {\n for (const line of chunk.toString().split(\"\\n\")) onLine(line);\n });\n input.proc.stderr?.on(\"data\", (chunk: Buffer) => {\n for (const line of chunk.toString().split(\"\\n\")) onLine(line);\n });\n}\n\n/** Attach process error/exit handlers for tunnel startup failures. */\nfunction attachTunnelLifecycle(input: {\n proc: ChildProcess;\n state: { publicUrl: string; settled: boolean };\n settle: (result: { url?: string; error?: Error }) => void;\n clear: () => void;\n}): void {\n input.proc.on(\"error\", (err) => {\n input.clear();\n input.settle({ error: err });\n });\n input.proc.on(\"exit\", (code) => {\n input.clear();\n if (code !== 0 && !input.state.publicUrl) {\n input.settle({ error: new Error(`cloudflared exited with code ${code}`) });\n }\n });\n}\n\n/** Wait until cloudflared prints a public trycloudflare.com URL. */\nfunction waitForTunnelUrl(proc: ChildProcess): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const state = { publicUrl: \"\", settled: false };\n const settle = (result: { url?: string; error?: Error }) => {\n if (state.settled) return;\n state.settled = true;\n if (result.error) reject(result.error);\n else resolve(result.url ?? \"\");\n };\n const timeout = setTimeout(() => {\n settle({ error: new Error(\"Timed out waiting for tunnel URL\") });\n }, 30_000);\n const clear = () => clearTimeout(timeout);\n attachTunnelOutput({ proc, state, settle, clear });\n attachTunnelLifecycle({ proc, state, settle, clear });\n });\n}\n\n/**\n * Backward-compatible class wrapper that manages a Cloudflare Tunnel subprocess.\n *\n * Callers that need a simple `new CloudflareTunnelClass()` with `start`/`stop`/`getUrl`\n * use this directly. For Effect-based consumers, prefer the `CloudflareTunnel` Tag and\n * `CloudflareTunnelLive` Layer.\n */\nexport class CloudflareTunnelClass {\n private proc: ChildProcess | null = null;\n private publicUrl = \"\";\n\n /**\n * Start the tunnel, returning the public HTTPS URL.\n *\n * @param localPort - The local port to expose.\n * @returns The public tunnel URL.\n */\n async start(localPort: number): Promise<string> {\n this.proc = spawnCloudflared(localPort);\n this.publicUrl = await waitForTunnelUrl(this.proc);\n return this.publicUrl;\n }\n\n /**\n * Get the current public URL (empty string if not started).\n *\n * @returns The current public URL.\n */\n getUrl(): string {\n return this.publicUrl;\n }\n\n /**\n * Stop the tunnel.\n */\n stop(): void {\n if (this.proc) {\n this.proc.kill(\"SIGTERM\");\n this.proc = null;\n }\n }\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { DEFAULT_CONTEXT_LIMIT, DEFAULT_MCP_PORT, DEFAULT_PERMISSION_MODE } from \"@/config\";\nimport type { BridgeConfig } from \"@/features/domain\";\nimport { configPath } from \"@/features/store\";\n\nconst DEFAULT_CONFIG: BridgeConfig = {\n repoPath: process.cwd(),\n provider: \"chatgpt\",\n mcpPort: DEFAULT_MCP_PORT,\n contextLimit: DEFAULT_CONTEXT_LIMIT,\n permissionMode: DEFAULT_PERMISSION_MODE,\n};\n\n/**\n * Load the target repo's config, falling back to defaults for missing fields.\n *\n * Config is repo-local (`<repoPath>/.bridge/config.json`), so the repo is the\n * input that locates the file — not a value read back from a global config.\n */\nexport async function loadConfig(\n repoPath: string,\n overrides?: Partial<BridgeConfig>,\n): Promise<BridgeConfig> {\n let file: Partial<BridgeConfig> = {};\n try {\n file = JSON.parse(await readFile(configPath(repoPath), \"utf-8\"));\n } catch {\n // first run in this repo — no config file yet\n }\n return { ...DEFAULT_CONFIG, ...file, repoPath, ...overrides };\n}\n\n/** Persist config to the repo's `.bridge/config.json` so the next session reuses it. */\nexport async function saveConfig(cfg: BridgeConfig): Promise<void> {\n const path = configPath(cfg.repoPath);\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, JSON.stringify(cfg, null, 2));\n}\n","import { findModelProfile } from \"@/features/domain\";\nimport type {\n BridgeConfig,\n ConnectorSetupResult,\n Message,\n ModelOption,\n ToolResult,\n} from \"@/features/domain\";\nimport { isSameChatGptConversation } from \"@/features/providers\";\nimport { type BrowserProvider, getBrowserProvider } from \"@/features/providers\";\nimport type { Page } from \"playwright\";\n\n/** Options for sending a prompt through the orchestrator. */\nexport interface SendPromptOptions {\n timeoutMs?: number;\n}\n\n/** Input for {@link Orchestrator.sendPrompt}. */\nexport interface SendPromptInput {\n content: string;\n timeoutMs?: number;\n /** Number of generated images to wait for before the turn settles (ChatGPT only). */\n expectImages?: number;\n}\n\n/** Input for {@link Orchestrator.openConnectorSetup}. */\nexport interface ConnectorSetupInput {\n connectorUrl: string;\n automatic?: boolean;\n connectorName?: string;\n}\n\n/** Events emitted by {@link Orchestrator} to listeners. */\nexport type OrchestratorEvent =\n | { type: \"message\"; message: Message }\n | { type: \"tool_call\"; name: string; arguments: Record<string, unknown> }\n | { type: \"tool_result\"; name: string; result: ToolResult }\n | { type: \"status\"; text: string }\n | { type: \"error\"; error: string }\n | { type: \"context_update\"; count: number; limit: number }\n | { type: \"conversation_synced\"; messages: Message[] }\n | { type: \"model_changed\"; model: string; contextLimit: number }\n | { type: \"reset\" };\n\n/** Callback registered via {@link Orchestrator.on}. */\nexport type OrchestratorListener = (event: OrchestratorEvent) => void;\n\nfunction requirePage(page: Page | null, emit: (event: OrchestratorEvent) => void): Page | null {\n if (page) return page;\n emit({ type: \"error\", error: \"Browser not connected.\" });\n return null;\n}\n\nfunction requirePageForPrompt(\n page: Page | null,\n emit: (event: OrchestratorEvent) => void,\n): Page | null {\n if (page) return page;\n emit({ type: \"error\", error: \"Browser not connected. Cannot send prompt.\" });\n return null;\n}\n\nfunction buildMessage(role: Message[\"role\"], content: string): Message {\n return { id: crypto.randomUUID(), role, content, timestamp: Date.now() };\n}\n\nfunction formatError(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction createOrchestratorEmitter() {\n const state = { listeners: [] as Array<(event: OrchestratorEvent) => void> };\n return {\n on(fn: (event: OrchestratorEvent) => void) {\n state.listeners.push(fn);\n return () => {\n state.listeners = state.listeners.filter((listener) => listener !== fn);\n };\n },\n emit(event: OrchestratorEvent) {\n for (const fn of state.listeners) fn(event);\n },\n };\n}\n\nfunction mapCapturedMessages(captured: Array<{ role: string; content: string }>): Message[] {\n return captured\n .filter(\n (message): message is { role: \"user\" | \"assistant\"; content: string } =>\n (message.role === \"user\" || message.role === \"assistant\") &&\n message.content.trim().length > 0,\n )\n .map((message) => ({\n id: `dom-${crypto.randomUUID()}`,\n role: message.role,\n content: message.content,\n timestamp: Date.now(),\n }));\n}\n\nfunction emitModelChanged(emit: (event: OrchestratorEvent) => void, modelName: string): void {\n const profile = findModelProfile(modelName);\n emit({ type: \"model_changed\", model: modelName, contextLimit: profile.contextWindow });\n}\n\nfunction emitModelDetected(emit: (event: OrchestratorEvent) => void, modelName: string): void {\n const profile = findModelProfile(modelName);\n emit({ type: \"status\", text: `Model: ${modelName}` });\n emit({ type: \"model_changed\", model: modelName, contextLimit: profile.contextWindow });\n}\n\nasync function detectModel(input: {\n page: Page | null;\n provider: BrowserProvider;\n modelName: string;\n emit: (event: OrchestratorEvent) => void;\n}): Promise<string> {\n if (!input.page) return input.modelName;\n // The live provider read is authoritative — never fall back to a persisted label,\n // which can be another provider's model bleeding across a `--provider` switch.\n const detected = await input.provider.detectCurrentModel(input.page);\n emitModelDetected(input.emit, detected);\n return detected;\n}\n\nfunction applySelectedModel(\n models: ModelOption[],\n emit: (event: OrchestratorEvent) => void,\n): string | null {\n const selected = models.find((model) => model.selected);\n if (!selected) return null;\n emitModelChanged(emit, selected.label);\n return selected.label;\n}\n\nasync function listModelsAction(input: {\n page: Page;\n provider: BrowserProvider;\n emit: (event: OrchestratorEvent) => void;\n setModelName: (name: string) => void;\n}): Promise<ModelOption[]> {\n const models = await input.provider.listAvailableModels(input.page);\n const selected = applySelectedModel(models, input.emit);\n if (selected) input.setModelName(selected);\n return models;\n}\n\nasync function switchModelAction(input: {\n page: Page;\n provider: BrowserProvider;\n query: string;\n emit: (event: OrchestratorEvent) => void;\n}): Promise<string> {\n input.emit({ type: \"status\", text: `Switching model to ${input.query}...` });\n const modelName = await input.provider.selectModel(input.page, input.query);\n emitModelChanged(input.emit, modelName);\n input.emit({ type: \"status\", text: `Model: ${modelName}` });\n return modelName;\n}\n\nasync function syncConversationMessages(input: {\n page: Page | null;\n provider: BrowserProvider;\n emit: (event: OrchestratorEvent) => void;\n}): Promise<Message[]> {\n if (!input.page) return [];\n const messages = mapCapturedMessages(await input.provider.captureAllMessages(input.page));\n if (messages.length === 0) return [];\n input.emit({ type: \"conversation_synced\", messages });\n return messages;\n}\n\nasync function navigateToConversationAction(input: {\n page: Page;\n provider: BrowserProvider;\n emit: (event: OrchestratorEvent) => void;\n url: string;\n}): Promise<Message[]> {\n input.emit({ type: \"status\", text: \"Navigating to conversation...\" });\n await input.provider.navigateToConversation(input.page, input.url);\n const messages = await syncConversationMessages(input);\n input.emit({ type: \"status\", text: \"Ready\" });\n return messages;\n}\n\nasync function newConversationAction(input: {\n page: Page;\n provider: BrowserProvider;\n emit: (event: OrchestratorEvent) => void;\n}): Promise<void> {\n input.emit({ type: \"status\", text: \"Starting new conversation...\" });\n await input.provider.newConversation(input.page);\n input.emit({ type: \"reset\" });\n input.emit({ type: \"status\", text: \"Ready — new conversation\" });\n}\n\nasync function rewindLastPromptAction(input: {\n page: Page;\n provider: BrowserProvider;\n emit: (event: OrchestratorEvent) => void;\n replacement?: string;\n}): Promise<Message[]> {\n input.emit({ type: \"status\", text: \"Rewinding last prompt...\" });\n await input.provider.rewindLastUserPrompt(input.page, input.replacement);\n const messages = await syncConversationMessages(input);\n input.emit({ type: \"status\", text: \"Ready — rewound last prompt\" });\n return messages;\n}\n\nasync function attachFilesAction(input: {\n page: Page;\n provider: BrowserProvider;\n paths: string[];\n emit: (event: OrchestratorEvent) => void;\n}): Promise<void> {\n input.emit({ type: \"status\", text: \"Attaching files...\" });\n await input.provider.attachFilesToPrompt(input.page, input.paths);\n input.emit({ type: \"status\", text: \"Files attached.\" });\n}\n\nasync function stopResponseAction(input: {\n page: Page;\n provider: BrowserProvider;\n emit: (event: OrchestratorEvent) => void;\n}): Promise<boolean> {\n const stopped = await input.provider.stopGenerating(input.page);\n input.emit({\n type: \"status\",\n text: stopped ? \"Stopped response.\" : \"No active response to stop.\",\n });\n return stopped;\n}\n\nasync function executeSendPrompt(\n input: SendPromptInput & {\n page: Page | null;\n provider: BrowserProvider;\n emit: (event: OrchestratorEvent) => void;\n pushMessage: (message: Message) => void;\n },\n): Promise<Message | null> {\n const userMsg = buildMessage(\"user\", input.content);\n input.pushMessage(userMsg);\n input.emit({ type: \"message\", message: userMsg });\n input.emit({ type: \"status\", text: `Waiting for ${input.provider.displayName}...` });\n const page = requirePageForPrompt(input.page, input.emit);\n if (!page) return null;\n try {\n const previousAssistantCount = await input.provider.countAssistantResponses(page);\n const previousLastAssistantText = await input.provider.captureLastResponse(page);\n await input.provider.injectPrompt(page, input.content);\n input.emit({ type: \"status\", text: `${input.provider.displayName} is responding...` });\n await input.provider.waitForResponse(page, {\n previousAssistantCount,\n previousLastAssistantText,\n timeout: input.timeoutMs,\n expectImages: input.expectImages,\n });\n const responseText = await input.provider.captureLastResponse(page);\n const assistantMsg = buildMessage(\"assistant\", responseText);\n input.pushMessage(assistantMsg);\n input.emit({ type: \"message\", message: assistantMsg });\n input.emit({ type: \"status\", text: \"Ready\" });\n return assistantMsg;\n } catch (err) {\n input.emit({ type: \"error\", error: formatError(err) });\n return null;\n }\n}\n\nasync function openConnectorSetup(\n input: ConnectorSetupInput & {\n page: Page | null;\n provider: BrowserProvider;\n emit: (event: OrchestratorEvent) => void;\n },\n): Promise<ConnectorSetupResult> {\n if (!input.provider.supportsMcpConnector || !input.provider.setupMcpConnector) {\n input.emit({ type: \"status\", text: \"Connector setup is not available for this provider.\" });\n return {\n connectorUrl: input.connectorUrl,\n completed: false,\n steps: [],\n warnings: [\n `${input.provider.displayName} web does not support custom MCP connectors.`,\n \"Use @file mentions for read-only repo context, or switch to ChatGPT for full MCP tools.\",\n ],\n };\n }\n if (!input.page) {\n input.emit({ type: \"error\", error: \"Browser not connected.\" });\n return {\n connectorUrl: input.connectorUrl,\n completed: false,\n steps: [],\n warnings: [\n `Browser not connected. Open ${input.provider.displayName} settings manually and add the connector URL.`,\n ],\n };\n }\n input.emit({\n type: \"status\",\n text: input.automatic\n ? `Syncing ${input.provider.displayName} connector...`\n : `Opening ${input.provider.displayName} connector setup...`,\n });\n const result = await input.provider.setupMcpConnector(input.page, input.connectorUrl, {\n automatic: input.automatic,\n connectorName: input.connectorName,\n });\n input.emit({\n type: \"status\",\n text: result.completed ? \"Connector ready.\" : \"Connector setup needs manual finish.\",\n });\n return result;\n}\n\nexport class Orchestrator {\n private readonly emitter = createOrchestratorEmitter();\n private messages: Message[] = [];\n private page: Page | null = null;\n private readonly provider: BrowserProvider;\n private modelName: string;\n\n constructor(\n private _config: BridgeConfig,\n provider?: BrowserProvider,\n ) {\n this.provider = provider ?? getBrowserProvider(_config.provider);\n this.modelName = _config.model ?? this.provider.defaultModel;\n }\n\n get browserProvider(): BrowserProvider {\n return this.provider;\n }\n get model(): string {\n return this.modelName;\n }\n get currentMessages(): Message[] {\n return this.messages;\n }\n\n /** Attach the Playwright page used for browser automation. */\n setPage(page: Page): void {\n this.page = page;\n this.detectModel().catch(() => {});\n }\n\n /** Subscribe to orchestrator events (status, messages, errors). */\n on(fn: (event: OrchestratorEvent) => void): () => void {\n return this.emitter.on(fn);\n }\n\n private emit(event: OrchestratorEvent): void {\n this.emitter.emit(event);\n }\n\n /** Detect and cache the current model from the browser UI. */\n async detectModel(): Promise<string> {\n this.modelName = await detectModel({\n page: this.page,\n provider: this.provider,\n modelName: this.modelName,\n emit: this.emit.bind(this),\n });\n return this.modelName;\n }\n\n /** Sync conversation history and emit ready status. */\n async start(): Promise<void> {\n this.messages = await syncConversationMessages({\n page: this.page,\n provider: this.provider,\n emit: this.emit.bind(this),\n });\n this.detectModel().catch(() => {});\n this.emit({ type: \"status\", text: \"Bridge ready. Type a prompt to begin.\" });\n }\n\n /** Send a user prompt and wait for the assistant response. */\n async sendPrompt(input: SendPromptInput): Promise<Message | null> {\n return executeSendPrompt({\n ...input,\n page: this.page,\n provider: this.provider,\n emit: this.emit.bind(this),\n pushMessage: (m) => {\n this.messages.push(m);\n },\n });\n }\n\n /** List sidebar conversations when a page is attached. */\n async listConversations() {\n return this.page ? this.provider.readSidebarConversations(this.page) : [];\n }\n\n /** List models available in the provider UI. */\n async listModels(): Promise<ModelOption[]> {\n const page = requirePage(this.page, this.emit.bind(this));\n return page\n ? listModelsAction({\n page,\n provider: this.provider,\n emit: this.emit.bind(this),\n setModelName: (name) => {\n this.modelName = name;\n },\n })\n : [];\n }\n\n /** Switch the active model using a label query. */\n async switchModel(query: string): Promise<string> {\n const page = requirePage(this.page, this.emit.bind(this));\n if (!page) return this.modelName;\n this.modelName = await switchModelAction({\n page,\n provider: this.provider,\n query,\n emit: this.emit.bind(this),\n });\n return this.modelName;\n }\n\n /** Navigate to a conversation URL and refresh cached messages. */\n async navigateToConversation(url: string): Promise<void> {\n const page = requirePage(this.page, this.emit.bind(this));\n if (page?.url() && isSameChatGptConversation(page.url(), url)) return;\n if (page) {\n this.messages = await navigateToConversationAction({\n page,\n provider: this.provider,\n emit: this.emit.bind(this),\n url,\n });\n }\n }\n\n /** Start a new conversation in the provider UI. */\n async newConversation(): Promise<void> {\n const page = requirePage(this.page, this.emit.bind(this));\n if (!page) return;\n await newConversationAction({ page, provider: this.provider, emit: this.emit.bind(this) });\n this.messages = [];\n }\n\n /** Rewind the last user prompt, optionally replacing its text. */\n async rewindLastPrompt(replacement?: string): Promise<void> {\n const page = requirePage(this.page, this.emit.bind(this));\n if (page) {\n this.messages = await rewindLastPromptAction({\n page,\n provider: this.provider,\n emit: this.emit.bind(this),\n replacement,\n });\n }\n }\n\n /** Stop the in-progress assistant response when possible. */\n async stopResponse(): Promise<boolean> {\n const page = requirePage(this.page, this.emit.bind(this));\n return page\n ? stopResponseAction({ page, provider: this.provider, emit: this.emit.bind(this) })\n : false;\n }\n\n /** Attach local files to the provider composer. */\n async attachFiles(paths: string[]): Promise<void> {\n const page = requirePage(this.page, this.emit.bind(this));\n if (page)\n await attachFilesAction({ page, provider: this.provider, paths, emit: this.emit.bind(this) });\n }\n\n /** Open or sync the ChatGPT MCP connector setup UI. */\n async openConnectorSetup(input: ConnectorSetupInput): Promise<ConnectorSetupResult> {\n return openConnectorSetup({\n ...input,\n page: this.page,\n provider: this.provider,\n emit: this.emit.bind(this),\n });\n }\n\n /** Emit shutdown status before the engine tears down. */\n async stop(): Promise<void> {\n this.emit({ type: \"status\", text: \"Shutting down...\" });\n }\n}\n","import { BridgeEngine, mcpConnectorUrl } from \"./internal/bridgeEngine.ts\";\n\nexport type {\n StartEngineOptions,\n AskEngineInput,\n ShutdownEngineInput,\n} from \"./bridgeEngineTypes.ts\";\nexport type { ContextCounter } from \"./internal/bridgeEngine.ts\";\nexport { BridgeEngine, mcpConnectorUrl };\n\n/**\n * Wire up and start a bridge engine: config, MCP server, optional tunnel and\n * browser, orchestrator, and a fresh session.\n */\nexport async function startEngine(options: Parameters<typeof BridgeEngine.start>[0] = {}) {\n return BridgeEngine.start(options);\n}\n","/** Outcome of asking one provider within a fan-out. */\nexport interface ProviderAskOutcome {\n ok: boolean;\n reply?: string;\n error?: string;\n elapsedMs: number;\n}\n\n/** Fan-out result keyed by provider id. */\nexport type FanoutResult = Record<string, ProviderAskOutcome>;\n\n/** Options for {@link fanoutAsk}. */\nexport interface FanoutOptions {\n /** Per-provider timeout in ms (default 300000). */\n timeoutMs?: number;\n /** Injectable clock for deterministic tests. */\n now?: () => number;\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number, provider: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`${provider} timed out after ${ms}ms`)), ms);\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n}\n\n/**\n * Ask one prompt across many providers concurrently. Never rejects — each provider's\n * outcome (reply, or error + elapsed) is captured independently, so one slow or failed\n * provider never blocks or fails the rest.\n */\nexport async function fanoutAsk(\n providers: string[],\n runOne: (provider: string) => Promise<string>,\n options: FanoutOptions = {},\n): Promise<FanoutResult> {\n const timeoutMs = options.timeoutMs ?? 300_000;\n const clock = options.now ?? (() => Date.now());\n const outcomes = await Promise.all(\n providers.map(async (provider): Promise<readonly [string, ProviderAskOutcome]> => {\n const start = clock();\n try {\n const reply = await withTimeout(runOne(provider), timeoutMs, provider);\n return [provider, { ok: true, reply, elapsedMs: clock() - start }];\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n return [provider, { ok: false, error, elapsedMs: clock() - start }];\n }\n }),\n );\n return Object.fromEntries(outcomes);\n}\n\n/** Whether the run should exit non-zero: all providers failed, or (strict) any failed. */\nexport function fanoutFailed(result: FanoutResult, strict: boolean): boolean {\n const outcomes = Object.values(result);\n if (outcomes.length === 0) return true;\n return strict ? outcomes.some((o) => !o.ok) : outcomes.every((o) => !o.ok);\n}\n","/**\n * Effect Schema definitions for the bridge feature.\n *\n * These schemas provide runtime validation and type derivation for the key\n * input/option types used by the bridge engine and fan-out orchestrator.\n * The existing implementations (`bridgeEngine.ts`, `orchestrator.ts`) remain\n * unchanged — these schemas are additive and exported through the door.\n *\n * @module\n */\nimport { Schema } from \"effect\";\n\nimport { PermissionModeSchema } from \"@/features/domain\";\n\n// ---------------------------------------------------------------------------\n// StartEngineOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the options accepted by {@link BridgeEngine.start}.\n */\nexport const StartEngineOptionsSchema = Schema.Struct({\n repoPath: Schema.optional(Schema.String).annotations({\n description: \"Target repository the MCP tools operate inside.\",\n }),\n provider: Schema.optional(Schema.String).annotations({\n description: \"Browser provider (e.g. 'chatgpt' or 'gemini').\",\n }),\n mcpPort: Schema.optional(Schema.Number).annotations({\n description: \"MCP server port. Defaults to the saved port or 8765.\",\n }),\n withBrowser: Schema.optional(Schema.Boolean).annotations({\n description: \"Launch/attach Chrome.\",\n }),\n withTools: Schema.optional(Schema.Boolean).annotations({\n description: \"Start the local MCP server. Defaults to true.\",\n }),\n withTunnel: Schema.optional(Schema.Boolean).annotations({\n description: \"Start the Cloudflare tunnel + sync the ChatGPT connector.\",\n }),\n});\n\n/**\n * StartEngineOptions type derived from the schema.\n */\nexport type StartEngineOptionsFromSchema = Schema.Schema.Type<typeof StartEngineOptionsSchema>;\n\n// ---------------------------------------------------------------------------\n// AskEngineInput\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the input to {@link BridgeEngine.ask}.\n */\nexport const AskEngineInputSchema = Schema.Struct({\n content: Schema.String.pipe(Schema.minLength(1)).annotations({\n description: \"User prompt text.\",\n }),\n timeoutMs: Schema.optional(Schema.Number.pipe(Schema.positive())).annotations({\n description: \"Optional timeout override in milliseconds.\",\n }),\n expectImages: Schema.optional(Schema.Number.pipe(Schema.int(), Schema.positive())).annotations({\n description: \"Number of generated images to wait for before returning (ChatGPT only).\",\n }),\n});\n\n/**\n * AskEngineInput type derived from the schema.\n */\nexport type AskEngineInputFromSchema = Schema.Schema.Type<typeof AskEngineInputSchema>;\n\n// ---------------------------------------------------------------------------\n// ShutdownEngineInput\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the input to {@link BridgeEngine.shutdown}.\n */\nexport const ShutdownEngineInputSchema = Schema.Struct({\n closeBrowser: Schema.optional(Schema.Boolean).annotations({\n description: \"Whether to close the browser on shutdown.\",\n }),\n});\n\n/**\n * ShutdownEngineInput type derived from the schema.\n */\nexport type ShutdownEngineInputFromSchema = Schema.Schema.Type<typeof ShutdownEngineInputSchema>;\n\n// ---------------------------------------------------------------------------\n// EngineRuntimeState\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the mutable session and permission state shared by engine methods.\n */\nexport const EngineRuntimeStateSchema = Schema.Struct({\n sessionId: Schema.String.annotations({\n description: \"Active session id for persistence.\",\n }),\n permissionMode: PermissionModeSchema.annotations({\n description: \"Current permission mode for MCP tool calls.\",\n }),\n});\n\n/**\n * EngineRuntimeState type derived from the schema.\n */\nexport type EngineRuntimeStateFromSchema = Schema.Schema.Type<typeof EngineRuntimeStateSchema>;\n\n// ---------------------------------------------------------------------------\n// FanoutOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the options accepted by {@link fanoutAsk}.\n */\nexport const FanoutOptionsSchema = Schema.Struct({\n timeoutMs: Schema.optional(Schema.Number.pipe(Schema.positive())).annotations({\n description: \"Per-provider timeout in ms (default 300000).\",\n }),\n});\n\n/**\n * FanoutOptions type derived from the schema.\n */\nexport type FanoutOptionsFromSchema = Schema.Schema.Type<typeof FanoutOptionsSchema>;\n\n// ---------------------------------------------------------------------------\n// ProviderAskOutcome\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the outcome of asking one provider within a fan-out.\n */\nexport const ProviderAskOutcomeSchema = Schema.Struct({\n ok: Schema.Boolean,\n reply: Schema.optional(Schema.String),\n error: Schema.optional(Schema.String),\n elapsedMs: Schema.Number,\n});\n\n/**\n * ProviderAskOutcome type derived from the schema.\n */\nexport type ProviderAskOutcomeFromSchema = Schema.Schema.Type<typeof ProviderAskOutcomeSchema>;\n","import { type BridgeProviderId, PROVIDER_CONFIG } from \"@/config\";\n\n/** Resolve a provider id to its human-readable display name. */\nexport function getProviderDisplayName(id: BridgeProviderId): string {\n return PROVIDER_CONFIG[id].displayName;\n}\n","import { Box } from \"ink\";\nimport { ComposerAssistPanel } from \"./ComposerAssistPanel.tsx\";\nimport { ComposerInputBar } from \"./ComposerInputBar.tsx\";\nimport { MessagePane } from \"./MessagePane.tsx\";\nimport { StatusBar } from \"./StatusBar.tsx\";\nimport type { AppProps } from \"./appTypes.ts\";\nimport { useComposer } from \"./useComposer.ts\";\n\nexport { getMessageRoleTheme, shouldAutoWrapProjectPrompt } from \"./roleThemeConfig.ts\";\nexport type { AppProps } from \"./appTypes.ts\";\n\n/** Terminal bridge Ink application root. */\nexport function BridgeApp(props: AppProps) {\n const view = useComposer(props);\n return (\n <Box flexDirection=\"column\" height=\"100%\">\n <MessagePane messages={props.messages} />\n <StatusBar {...view.statusBar} />\n <ComposerInputBar {...view.inputBar} />\n <ComposerAssistPanel {...view.assistPanel} />\n </Box>\n );\n}\n","import type { CommandDef } from \"@/features/domain\";\nimport { Box, Text } from \"ink\";\nimport {\n CommandFallbackMenu,\n FileMentions,\n QueuedPromptPreview,\n SuggestionMenu,\n TypingSuggestionMenu,\n} from \"./ComposerAssistSections.tsx\";\nimport type { InputMode } from \"./appTypes.ts\";\nimport { ASSIST_PANEL_HEIGHT } from \"./composerConstants.ts\";\nimport type { InputSuggestionGroup } from \"./inputSuggestions.ts\";\n\n/** Props for the composer assist panel below the input bar. */\nexport type ComposerAssistPanelProps = {\n /** Current composer input mode. */\n mode: InputMode;\n /** Loaded input suggestions, if any. */\n inputSuggestions: InputSuggestionGroup | null;\n /** Slash commands matching the current prefix. */\n matches: readonly CommandDef[];\n /** Selected suggestion or command index. */\n selectedIdx: number;\n /** File mentions detected in the current input. */\n fileMentions: readonly string[];\n /** Queued prompt waiting for the active response. */\n queuedPrompt: string | null;\n};\n\n/** Renders command, suggestion, file, and queue hints beneath the input. */\nexport function ComposerAssistPanel(props: ComposerAssistPanelProps) {\n const flags = assistPanelFlags(props);\n return (\n <Box flexDirection=\"column\" height={ASSIST_PANEL_HEIGHT} paddingX={1}>\n {flags.showCommandSuggestions && props.inputSuggestions && (\n <SuggestionMenu suggestions={props.inputSuggestions} selectedIdx={props.selectedIdx} />\n )}\n {flags.showCommandFallback && (\n <CommandFallbackMenu matches={props.matches} selectedIdx={props.selectedIdx} />\n )}\n {flags.showTypingSuggestions && props.inputSuggestions && (\n <TypingSuggestionMenu suggestions={props.inputSuggestions} />\n )}\n {flags.showFiles && <FileMentions fileMentions={props.fileMentions} />}\n {props.queuedPrompt && <QueuedPromptPreview prompt={props.queuedPrompt} />}\n <Text dimColor>\n Ctrl+R history | Up/Down history | Tab suggestion | paste multiline text, Enter sends\n </Text>\n </Box>\n );\n}\n\nfunction assistPanelFlags(props: ComposerAssistPanelProps) {\n const suggestions = props.inputSuggestions?.suggestions ?? [];\n return {\n showCommandSuggestions: props.mode === \"command-list\" && suggestions.length > 0,\n showCommandFallback:\n props.mode === \"command-list\" && suggestions.length === 0 && props.matches.length > 0,\n showTypingSuggestions: props.mode === \"typing\" && Boolean(props.inputSuggestions),\n showFiles: props.fileMentions.length > 0 && !props.inputSuggestions,\n };\n}\n","import type { CommandDef } from \"@/features/domain\";\nimport { Box, Text } from \"ink\";\nimport { VISIBLE_SUGGESTION_LIMIT } from \"./composerConstants.ts\";\nimport type { InputSuggestionGroup } from \"./inputSuggestions.ts\";\nimport { visibleMenuItems } from \"./visibleMenuItems.ts\";\n\nexport function SuggestionMenu(props: { suggestions: InputSuggestionGroup; selectedIdx: number }) {\n const rows = visibleMenuItems({\n items: props.suggestions.suggestions,\n selectedIdx: props.selectedIdx,\n limit: VISIBLE_SUGGESTION_LIMIT,\n });\n return (\n <>\n <Text dimColor>{props.suggestions.title}:</Text>\n {rows.map(({ item, index }) => (\n <SuggestionRow\n key={`${item.kind}:${item.value}`}\n label={item.label}\n detail={item.detail}\n selected={index === props.selectedIdx}\n />\n ))}\n {props.suggestions.hint && <Text dimColor> {props.suggestions.hint}</Text>}\n </>\n );\n}\n\nfunction SuggestionRow(props: { label: string; detail?: string; selected: boolean }) {\n return (\n <Box>\n <Text>\n {props.selected ? (\n <Text color=\"cyan\" bold>\n {\">\"}\n </Text>\n ) : (\n \" \"\n )}{\" \"}\n <Text color={props.selected ? \"cyan\" : \"white\"} bold={props.selected}>\n {props.label.padEnd(16)}\n </Text>\n {props.detail ? <Text dimColor> {props.detail}</Text> : null}\n </Text>\n </Box>\n );\n}\n\nexport function CommandFallbackMenu(props: {\n matches: readonly CommandDef[];\n selectedIdx: number;\n}) {\n const rows = visibleMenuItems({\n items: props.matches,\n selectedIdx: props.selectedIdx,\n limit: VISIBLE_SUGGESTION_LIMIT,\n });\n return (\n <>\n <Text dimColor>Commands:</Text>\n {rows.map(({ item, index }) => (\n <Box key={item.name}>\n <Text>\n {index === props.selectedIdx ? (\n <Text color=\"cyan\" bold>\n {\">\"}\n </Text>\n ) : (\n \" \"\n )}\n {\" /\"}\n <Text\n color={index === props.selectedIdx ? \"cyan\" : \"white\"}\n bold={index === props.selectedIdx}\n >\n {item.name.padEnd(14)}\n </Text>\n <Text dimColor> {item.description}</Text>\n </Text>\n </Box>\n ))}\n {props.matches.length > VISIBLE_SUGGESTION_LIMIT && (\n <Text dimColor> ... and {props.matches.length - VISIBLE_SUGGESTION_LIMIT} more</Text>\n )}\n </>\n );\n}\n\nexport function TypingSuggestionMenu(props: { suggestions: InputSuggestionGroup }) {\n return (\n <>\n <Text dimColor>{props.suggestions.title}:</Text>\n {props.suggestions.suggestions\n .slice(0, VISIBLE_SUGGESTION_LIMIT)\n .map((...args: [InputSuggestionGroup[\"suggestions\"][number], number]) => (\n <Text key={`${args[0].kind}:${args[0].value}`}>\n {args[1] === 0 ? (\n <Text color=\"cyan\" bold>\n {\">\"}\n </Text>\n ) : (\n \" \"\n )}{\" \"}\n <Text color={args[1] === 0 ? \"cyan\" : \"white\"}>{args[0].label}</Text>\n {args[0].detail ? <Text dimColor> {args[0].detail}</Text> : null}\n </Text>\n ))}\n {props.suggestions.hint && <Text dimColor> {props.suggestions.hint}</Text>}\n </>\n );\n}\n\nexport function FileMentions(props: { fileMentions: readonly string[] }) {\n return (\n <Text>\n <Text dimColor>Files: </Text>\n <Text color=\"cyan\">{props.fileMentions.map((file) => `@${file}`).join(\" \")}</Text>\n </Text>\n );\n}\n\nexport function QueuedPromptPreview(props: { prompt: string }) {\n return (\n <Text>\n <Text dimColor>Queued: </Text>\n <Text color=\"yellow\">{props.prompt.slice(0, 80)}</Text>\n </Text>\n );\n}\n","export const ESCAPE_CONTROL = \"\\u001B\";\nexport const ASSIST_PANEL_HEIGHT = 10;\nexport const VISIBLE_SUGGESTION_LIMIT = 6;\n","/** A menu item paired with its absolute index in the source list. */\nexport type VisibleMenuItem<T> = {\n /** The underlying menu item. */\n item: T;\n /** Absolute index in the full list. */\n index: number;\n};\n\n/** Options for slicing a menu around the selected index. */\nexport type VisibleMenuItemsOptions<T> = {\n /** Full list of menu items. */\n items: readonly T[];\n /** Currently selected index. */\n selectedIdx: number;\n /** Maximum number of visible rows. */\n limit: number;\n};\n\n/** Returns a window of menu items centered around the selected index. */\nexport function visibleMenuItems<T>(options: VisibleMenuItemsOptions<T>): VisibleMenuItem<T>[] {\n const { items, selectedIdx, limit } = options;\n const safeSelected = Math.min(Math.max(selectedIdx, 0), Math.max(items.length - 1, 0));\n const start = Math.max(0, Math.min(safeSelected - limit + 1, items.length - limit));\n return items.slice(start, start + limit).map((...args: [T, number]) => ({\n item: args[0],\n index: start + args[1],\n }));\n}\n","import { Box, Text } from \"ink\";\nimport TextInput from \"ink-text-input\";\n\n/** Props for the composer input row. */\nexport type ComposerInputBarProps = {\n /** Current input value. */\n input: string;\n /** Input change handler. */\n onChange: (value: string) => void;\n /** Submit handler. */\n onSubmit: (value: string) => void;\n};\n\n/** Renders the prompt input row. */\nexport function ComposerInputBar(props: ComposerInputBarProps) {\n return (\n <Box paddingX={1}>\n <Text color=\"cyan\">{\">\"} </Text>\n <TextInput value={props.input} onChange={props.onChange} onSubmit={props.onSubmit} />\n </Box>\n );\n}\n","import type { Message } from \"@/features/domain\";\nimport { Box, Text } from \"ink\";\nimport { getMessageRoleTheme } from \"./roleThemeConfig.ts\";\n\n/** Props for the scrollable message pane. */\nexport type MessagePaneProps = {\n /** Messages to render. */\n messages: Message[];\n};\n\n/** Renders the conversation message list. */\nexport function MessagePane(props: MessagePaneProps) {\n return (\n <Box flexDirection=\"column\" flexGrow={1} overflowY=\"hidden\">\n {props.messages.map((message) => (\n <MessageRow key={message.id} message={message} />\n ))}\n </Box>\n );\n}\n\n/** Props for a single rendered message row. */\ntype MessageRowProps = {\n /** Message to display. */\n message: Message;\n};\n\nfunction MessageRow(props: MessageRowProps) {\n const theme = getMessageRoleTheme(props.message.role);\n const preview = formatMessagePreview(props.message.content);\n\n return (\n <Box flexDirection=\"column\" marginBottom={0}>\n <Text>\n <Text color={theme.color} backgroundColor={theme.backgroundColor} bold>\n {theme.prefix} {theme.label}:{\" \"}\n </Text>{\" \"}\n <Text color={theme.color} backgroundColor={theme.backgroundColor}>\n {preview}\n </Text>\n </Text>\n {renderToolCalls(props.message)}\n </Box>\n );\n}\n\nfunction formatMessagePreview(content: string): string {\n if (content.length <= 500) return content;\n return `${content.slice(0, 500)}...`;\n}\n\nfunction renderToolCalls(message: Message) {\n if (!message.toolCalls?.length) return null;\n return (\n <Box marginLeft={2}>\n <Text dimColor>[tools: {message.toolCalls.map((toolCall) => toolCall.name).join(\", \")}]</Text>\n </Box>\n );\n}\n","import type { Message } from \"@/features/domain\";\n\n/** Visual theme applied to a terminal message by role. */\nexport type MessageRoleTheme = {\n /** Foreground ink color. */\n color: string;\n /** Background ink color. */\n backgroundColor: string;\n /** Human-readable role label. */\n label: \"You\" | \"ChatGPT\";\n /** Prefix glyph shown before the label. */\n prefix: \">\" | \"<\";\n};\n\nconst MESSAGE_ROLE_THEMES: Record<Message[\"role\"], MessageRoleTheme> = {\n user: {\n color: \"white\",\n backgroundColor: \"blue\",\n label: \"You\",\n prefix: \">\",\n },\n assistant: {\n color: \"white\",\n backgroundColor: \"blackBright\",\n label: \"ChatGPT\",\n prefix: \"<\",\n },\n};\n\n/** Returns the terminal theme for a message role. */\nexport function getMessageRoleTheme(role: Message[\"role\"]): MessageRoleTheme {\n return MESSAGE_ROLE_THEMES[role];\n}\n\n/** Returns true when a free-form prompt should be wrapped with project instructions. */\nexport function shouldAutoWrapProjectPrompt(input: string): boolean {\n const text = input.toLowerCase();\n if (/@[\\w./-]+/.test(input)) return true;\n\n const hasProjectNoun =\n /\\b(repo|repository|project|codebase|local|file|files|folder|folders|structure|src|test|tests|package|readme)\\b/.test(\n text,\n );\n const hasAction =\n /\\b(check|inspect|read|review|analyze|analyse|find|fix|debug|change|edit|update|add|implement|refactor|optimize|optimise|run|test|verify|qa|explain)\\b/.test(\n text,\n );\n return hasProjectNoun && hasAction;\n}\n","import { Box, Text } from \"ink\";\nimport { buildStatusBarProps } from \"./statusBarHelpers.ts\";\n\n/** Props for the compact status bar above the composer. */\nexport type StatusBarProps = {\n /** Short status message. */\n shortStatus: string;\n /** Context usage percentage color. */\n ctxColor: string;\n /** Context usage percentage label. */\n ctxPctLabel: string;\n /** Short model label. */\n shortModel: string;\n /** Permission mode label. */\n displayPermissionMode: string;\n /** Tool call count label. */\n displayToolCallCount: number;\n /** Short branch label. */\n shortBranch: string;\n /** Short session id label. */\n displaySessionId: string;\n};\n\nexport { buildStatusBarProps };\n\n/** Renders the compact status bar above the composer. */\nexport function StatusBar(props: StatusBarProps) {\n return (\n <Box borderStyle=\"single\" borderColor=\"gray\" paddingX={1}>\n <Text dimColor>{props.shortStatus}</Text>\n <Text> | </Text>\n <Text color={props.ctxColor}>ctx {props.ctxPctLabel}</Text>\n <Text> | </Text>\n <Text color=\"magenta\">{props.shortModel}</Text>\n <Text> | </Text>\n <Text dimColor>p:{props.displayPermissionMode}</Text>\n <Text> | </Text>\n <Text dimColor>t:{props.displayToolCallCount}</Text>\n <Text> | </Text>\n <Text dimColor>{props.shortBranch}</Text>\n <Text> | </Text>\n <Text dimColor>{props.displaySessionId}</Text>\n </Box>\n );\n}\n","import type { ContextCounter } from \"@/features/bridge\";\nimport type { StatusBarProps } from \"./StatusBar.tsx\";\nimport type { AppProps } from \"./appTypes.ts\";\n\n/** Resolved display values for the status bar. */\ninterface StatusBarDisplay {\n displayPermissionMode: string;\n displayToolCallCount: number;\n displayBranch?: string;\n displaySessionId?: string;\n}\n\n/** Builds status bar display props from app props and runtime status. */\nexport function buildStatusBarProps(options: {\n props: AppProps;\n status: string;\n counter: ContextCounter;\n}): StatusBarProps {\n const { props, status, counter } = options;\n const ctxPct = counter.fraction * 100;\n const display = resolveStatusBarDisplay(props);\n return {\n shortStatus: truncateText({ value: status, maxLength: 14 }),\n ctxColor: ctxPct > 80 ? \"red\" : ctxPct > 50 ? \"yellow\" : \"green\",\n ctxPctLabel: `${ctxPct.toFixed(0)}%`,\n shortModel: truncateText({ value: counter.modelLabel, maxLength: 10 }),\n displayPermissionMode: display.displayPermissionMode,\n displayToolCallCount: display.displayToolCallCount,\n shortBranch: display.displayBranch\n ? truncateText({ value: display.displayBranch, maxLength: 8 })\n : \"nogit\",\n displaySessionId: display.displaySessionId ? display.displaySessionId.slice(0, 8) : \"nosess\",\n };\n}\n\n/** Resolve permission, tool, branch, and session labels for the status bar. */\nfunction resolveStatusBarDisplay(props: AppProps): StatusBarDisplay {\n return {\n displayPermissionMode:\n props.permission?.getMode() ?? props.permissionMode ?? props.config.permissionMode ?? \"auto\",\n displayToolCallCount: props.statusline?.toolCallCount() ?? props.toolCallCount ?? 0,\n displayBranch: props.statusline?.branch ?? props.branch,\n displaySessionId: props.session?.getId() ?? props.sessionId,\n };\n}\n\nfunction truncateText(input: { value: string; maxLength: number }): string {\n if (input.value.length <= input.maxLength) return input.value;\n return `${input.value.slice(0, input.maxLength - 1)}…`;\n}\n","import type { CommandContext } from \"@/features/domain\";\nimport { useCallback, useMemo } from \"react\";\nimport { executeCommand } from \"../internal/cliRunner.ts\";\nimport type { PromptSendResult } from \"./appTypes.ts\";\nimport type { AppProps } from \"./appTypes.ts\";\nimport { projectAwarePrompt } from \"./projectAwarePrompt.ts\";\nimport type { ComposerState } from \"./useComposerState.ts\";\n\n/** Options for slash command execution. */\nexport type ComposerCommandOptions = {\n /** Composer state container. */\n state: ComposerState;\n /** App props used to build command context. */\n props: AppProps;\n /** Prompt send handler. */\n enqueueOrSendPrompt: (prompt: string) => Promise<PromptSendResult>;\n};\n\n/** Creates command context and runCommand handler. */\nexport function useComposerCommands(options: ComposerCommandOptions) {\n const ctx = useCommandContext(options.props);\n const runCommand = useRunCommand({ ...options, ctx });\n return runCommand;\n}\n\nfunction useCommandContext(props: AppProps): CommandContext {\n return useMemo(\n () => ({\n config: props.config,\n messages: props.messages,\n sendMessage: props.sendMessage,\n clearMessages: props.clearMessages,\n shutdown: props.shutdown,\n counter: props.counter,\n orchestrator: props.orchestrator,\n permission: props.permission,\n session: props.session,\n statusline: props.statusline,\n }),\n [props],\n );\n}\n\nfunction useRunCommand(options: ComposerCommandOptions & { ctx: CommandContext }) {\n const { state, enqueueOrSendPrompt, ctx } = options;\n return useCallback(\n async (cmd: string) => {\n try {\n await executeCommandOrPrompt({ cmd, ctx, state, enqueueOrSendPrompt });\n } catch (err) {\n reportCommandError({ state, err });\n } finally {\n state.forceRender((value) => value + 1);\n }\n },\n [ctx, enqueueOrSendPrompt, state],\n );\n}\n\nasync function executeCommandOrPrompt(options: {\n cmd: string;\n ctx: CommandContext;\n state: ComposerState;\n enqueueOrSendPrompt: (prompt: string) => Promise<PromptSendResult>;\n}) {\n const handled = await executeCommand(options.cmd, options.ctx);\n if (handled) {\n options.state.setStatus(\"Ready\");\n return;\n }\n if (options.cmd.startsWith(\"/\")) {\n reportUnknownCommand({ state: options.state, cmd: options.cmd });\n return;\n }\n await sendProjectAwarePrompt(options);\n}\n\n/** Send a non-command prompt through the project-aware wrapper. */\nasync function sendProjectAwarePrompt(options: {\n cmd: string;\n ctx: CommandContext;\n state: ComposerState;\n enqueueOrSendPrompt: (prompt: string) => Promise<PromptSendResult>;\n}): Promise<void> {\n const prompt = await projectAwarePrompt({ input: options.cmd, ctx: options.ctx });\n const sendResult = await options.enqueueOrSendPrompt(prompt);\n if (sendResult === \"queued\") return;\n options.state.setStatus(\"Ready\");\n}\n\nfunction reportUnknownCommand(input: { state: ComposerState; cmd: string }) {\n const name = input.cmd.slice(1).split(\" \")[0] || \"/\";\n input.state.setStatus(`Unknown command: /${name}`);\n console.error(`Unknown command: /${name}`);\n}\n\nfunction reportCommandError(input: { state: ComposerState; err: unknown }) {\n const message = input.err instanceof Error ? input.err.message : String(input.err);\n input.state.setStatus(`Error: ${message}`);\n console.error(message);\n}\n","import type { CommandContext } from \"@/features/domain\";\nimport { loadProjectInstructions } from \"@/features/user-config\";\nimport { buildProjectTaskPromptWithInstructions } from \"../internal/cliRunner.ts\";\nimport { shouldAutoWrapProjectPrompt } from \"./roleThemeConfig.ts\";\n\n/** Options for building a project-aware prompt. */\nexport type ProjectAwarePromptOptions = {\n /** Raw user input. */\n input: string;\n /** Command execution context. */\n ctx: CommandContext;\n};\n\n/** Wraps input with project instructions when the prompt looks repo-related. */\nexport async function projectAwarePrompt(options: ProjectAwarePromptOptions): Promise<string> {\n const { input, ctx } = options;\n if (!shouldAutoWrapProjectPrompt(input)) return input;\n const instructions = await loadProjectInstructions(ctx.config.repoPath);\n return buildProjectTaskPromptWithInstructions(input, ctx, instructions.promptText);\n}\n","import { useCallback } from \"react\";\nimport type { InputMode } from \"./appTypes.ts\";\nimport { ESCAPE_CONTROL } from \"./composerConstants.ts\";\nimport type { ComposerState } from \"./useComposerState.ts\";\n\n/** Options for composer text input handlers. */\nexport type ComposerInputHandlersOptions = {\n /** Composer state container. */\n state: ComposerState;\n /** Slash command runner. */\n runCommand: (cmd: string) => Promise<void>;\n};\n\n/** Creates input change and submit handlers. */\nexport function useComposerInputHandlers(options: ComposerInputHandlersOptions) {\n const handleInputChange = useHandleInputChange(options.state);\n const handleSubmit = useHandleSubmit(options);\n return { handleInputChange, handleSubmit };\n}\n\nfunction useHandleInputChange(state: ComposerState) {\n return useCallback(\n (value: string) => {\n if (stripEscapeControl({ state, value })) return;\n applyInputValue({ state, value });\n },\n [state],\n );\n}\n\nfunction stripEscapeControl(input: { state: ComposerState; value: string }) {\n if (!input.value.includes(ESCAPE_CONTROL)) return false;\n input.state.setInput(input.value.replaceAll(ESCAPE_CONTROL, \"\"));\n return true;\n}\n\nfunction applyInputValue(input: { state: ComposerState; value: string }) {\n input.state.refs.lastEscapeAt.current = 0;\n input.state.setInput(input.value);\n updateInputMode({ state: input.state, value: input.value });\n}\n\nfunction updateInputMode(input: { state: ComposerState; value: string }) {\n const mode = resolveInputMode(input.value);\n input.state.setMode(mode);\n if (mode === \"command-list\") input.state.setSelectedIdx(0);\n}\n\nfunction resolveInputMode(value: string): InputMode {\n if (!value.startsWith(\"/\")) return \"typing\";\n if (!value.includes(\" \")) return \"command-list\";\n return \"typing\";\n}\n\nfunction useHandleSubmit(options: ComposerInputHandlersOptions) {\n const { state, runCommand } = options;\n return useCallback(\n async (value: string) => {\n await submitComposerInput({ state, runCommand, value });\n },\n [runCommand, state],\n );\n}\n\n/** Handle one composer submit, including history and slash-only clears. */\nasync function submitComposerInput(input: {\n state: ComposerState;\n runCommand: (cmd: string) => Promise<void>;\n value: string;\n}): Promise<void> {\n if (consumeSuppressedSubmit(input.state)) return;\n const trimmed = input.value.trim();\n if (!trimmed || trimmed === \"/\") return clearSlashOnly(input.state);\n await runSubmittedPrompt({ state: input.state, runCommand: input.runCommand, trimmed });\n}\n\n/** Skip submit when the previous menu selection already dispatched a command. */\nfunction consumeSuppressedSubmit(state: ComposerState): boolean {\n if (!state.refs.suppressNextSubmit.current) return false;\n state.refs.suppressNextSubmit.current = false;\n return true;\n}\n\n/** Record history and dispatch a trimmed prompt. */\nasync function runSubmittedPrompt(input: {\n state: ComposerState;\n runCommand: (cmd: string) => Promise<void>;\n trimmed: string;\n}): Promise<void> {\n input.state.refs.history.current.add(input.trimmed);\n input.state.setInput(\"\");\n input.state.setMode(\"typing\");\n await input.runCommand(input.trimmed);\n}\n\nfunction clearSlashOnly(state: ComposerState) {\n state.setInput(\"\");\n state.setMode(\"typing\");\n}\n","import { useApp, useInput } from \"ink\";\nimport { useCallback } from \"react\";\nimport type { ComposerKeyboardOptions } from \"./composerKeyboardTypes.ts\";\nimport { handleCommandListKeys } from \"./useComposerKeyboardCommand.ts\";\nimport { handleGlobalShortcuts, handleTypingKeys } from \"./useComposerKeyboardTyping.ts\";\nimport type { ComposerState } from \"./useComposerState.ts\";\n\nexport type { ComposerKeyboardOptions } from \"./composerKeyboardTypes.ts\";\n\n/** Registers Ink keyboard handlers for the composer. */\nexport function useComposerKeyboard(options: ComposerKeyboardOptions) {\n const { exit } = useApp();\n useInput(\n (\n ...args: [\n string,\n {\n ctrl?: boolean;\n upArrow?: boolean;\n downArrow?: boolean;\n tab?: boolean;\n return?: boolean;\n },\n ]\n ) => {\n const char = args[0];\n const key = args[1];\n if (handleGlobalShortcuts({ char, key, exit, state: options.state })) return;\n if (options.state.mode === \"command-list\" && handleCommandListKeys({ char, key, ...options }))\n return;\n if (options.state.mode === \"typing\") handleTypingKeys({ char, key, ...options });\n },\n );\n}\n\n/** Creates the tab-complete handler for slash commands. */\nexport function useComposerTabComplete(state: ComposerState) {\n return useCallback(() => {\n if (state.matches.length === 0) return;\n const cmd = state.matches[state.selectedIdx] ?? state.matches[0];\n if (!cmd) return;\n state.setInput(`/${cmd.name} `);\n state.setMode(\"typing\");\n }, [state]);\n}\n","import { PERMISSION_MODES } from \"@/features/domain\";\nimport type { CommandSuggestionRule } from \"./types.ts\";\n\n/** Suggestion rules keyed by built-in slash command name. */\nexport const COMMAND_SUGGESTION_RULES: Record<string, CommandSuggestionRule> = {\n help: { title: \"Help\", hint: \"Press Enter to list commands.\" },\n conversations: {\n title: \"Conversations\",\n hint: \"Press Enter to list browser conversations, or type a title/id filter.\",\n },\n resume: {\n title: \"Resume\",\n hint: \"Choose --last, a local session id, or type a browser conversation title/id.\",\n },\n open: {\n title: \"Resume\",\n hint: \"Alias for /resume. Choose --last, a local session id, or type a browser conversation title/id.\",\n },\n new: { title: \"New Conversation\", hint: \"Press Enter to start a new ChatGPT conversation.\" },\n model: { title: \"Models\", hint: \"Choose a known model label, or type a browser model name.\" },\n rewind: {\n title: \"Rewind\",\n hint: \"Type replacement prompt text, or choose --files/--both then a checkpoint id.\",\n },\n retry: {\n title: \"Rewind\",\n hint: \"Alias for /rewind. Type replacement prompt text, or choose --files/--both then a checkpoint id.\",\n },\n stop: { title: \"Stop\", hint: \"Press Enter to stop the active ChatGPT response.\" },\n compact: { title: \"Compact\", hint: \"Press Enter to ask ChatGPT for a concise progress summary.\" },\n task: { title: \"Task\", hint: \"Type the project task. Use @ to mention files and folders.\" },\n work: {\n title: \"Task\",\n hint: \"Alias for /task. Type the project task. Use @ to mention files and folders.\",\n },\n commands: { title: \"Custom Commands\", hint: \"Press Enter to list project/user custom commands.\" },\n context: { title: \"Context\", hint: \"Press Enter to show context usage.\" },\n logs: { title: \"Logs\", hint: \"Press Enter to show today's local bridge log path.\" },\n sessions: { title: \"Sessions\", hint: \"Press Enter to list local bridge sessions.\" },\n transcript: {\n title: \"Transcript\",\n hint: \"Choose a local session id, or press Enter for the current session.\",\n },\n copy: {\n title: \"Copy\",\n hint: \"Choose a local session id, or press Enter for the current session transcript.\",\n },\n export: {\n title: \"Export\",\n hint: \"Choose a session id, or type an output path ending in .md, .json, or .jsonl.\",\n },\n permissions: {\n title: \"Permissions\",\n hint: \"Choose the MCP tool permission mode.\",\n values: PERMISSION_MODES.map((mode) => ({\n value: mode,\n label: mode,\n kind: \"mode\" as const,\n detail:\n mode === \"auto\"\n ? \"allow narrow write/test tools\"\n : mode === \"ask\"\n ? \"block until confirmation exists\"\n : \"read tools only\",\n })),\n },\n checkpoints: { title: \"Checkpoints\", hint: \"Press Enter to list file checkpoints.\" },\n restore: {\n title: \"Restore\",\n hint: \"Choose a checkpoint id, then optionally type repo paths to restore.\",\n },\n review: {\n title: \"Review\",\n hint: \"Choose review scope.\",\n values: [\n { value: \"working\", label: \"working\", kind: \"scope\", detail: \"review current working tree\" },\n { value: \"base\", label: \"base\", kind: \"scope\", detail: \"review against base branch\" },\n { value: \"commit\", label: \"commit\", kind: \"scope\", detail: \"review a commit\" },\n ],\n },\n status: { title: \"Status\", hint: \"Press Enter to show bridge status.\" },\n statusline: { title: \"Statusline\", hint: \"Press Enter to show status bar fields.\" },\n mcp: {\n title: \"MCP\",\n hint: \"Press Enter to show connector setup, exposed tools, and troubleshooting steps.\",\n },\n connector: {\n title: \"Connector\",\n hint: \"Press Enter to open ChatGPT Apps setup and fill the current Connector URL when possible.\",\n },\n clear: {\n title: \"Clear\",\n hint: \"Press Enter to clear the terminal chat view. Browser conversation and logs remain unchanged.\",\n },\n \"attach-image\": {\n title: \"Attach Image\",\n hint: \"Choose a repo image file. Directories are shown for navigation.\",\n },\n screenshot: {\n title: \"Screenshot\",\n hint: \"Type a http:// or https:// URL to capture desktop/mobile screenshots.\",\n values: [{ value: \"https://\", label: \"https://\", kind: \"url\" }],\n },\n \"ui-qa\": {\n title: \"UI QA\",\n hint: \"Type a http:// or https:// URL to capture screenshots and request UI review.\",\n values: [{ value: \"https://\", label: \"https://\", kind: \"url\" }],\n },\n diff: { title: \"Diff\", hint: \"Press Enter to ask ChatGPT to inspect the current git diff.\" },\n files: {\n title: \"Files\",\n hint: \"Press Enter to list attachments, or type get <id> / get all [--out <dir>] to download.\",\n values: [\n {\n value: \"get\",\n label: \"get\",\n kind: \"text\",\n detail: \"download an attachment by id, or 'all'\",\n },\n { value: \"get all\", label: \"get all\", kind: \"text\", detail: \"download every attachment\" },\n { value: \"--out\", label: \"--out\", kind: \"flag\", detail: \"output directory for downloads\" },\n ],\n },\n exit: { title: \"Exit\", hint: \"Press Enter to shut down the bridge.\" },\n};\n","import { isAbsolute, sep } from \"node:path\";\nimport type { ActiveFileMention, FileCompletionMatch } from \"./fileAutocompleteTypes.ts\";\n\ninterface FindMentionInput {\n /** Full composer input text. */\n input: string;\n /** Cursor position within the input. */\n cursor?: number;\n}\n\n/** Find the active `@file` mention span before the cursor. */\nexport function findActiveFileMention(\n input: FindMentionInput | string,\n cursor?: number,\n): ActiveFileMention | null {\n const text = typeof input === \"string\" ? input : input.input;\n const position =\n typeof input === \"string\" ? (cursor ?? text.length) : (input.cursor ?? text.length);\n return parseActiveFileMention({ text, position });\n}\n\n/** Parse an active `@file` mention ending at the cursor position. */\nfunction parseActiveFileMention(input: {\n text: string;\n position: number;\n}): ActiveFileMention | null {\n const beforeCursor = input.text.slice(0, input.position);\n const start = beforeCursor.lastIndexOf(\"@\");\n if (start === -1 || !isMentionBoundary({ beforeCursor, start })) return null;\n return readMentionPartial({ start, beforeCursor, position: input.position });\n}\n\n/** Read the partial mention text when the span is valid. */\nfunction readMentionPartial(input: {\n start: number;\n beforeCursor: string;\n position: number;\n}): ActiveFileMention | null {\n const partial = input.beforeCursor.slice(input.start + 1);\n if (/\\s/.test(partial)) return null;\n return { start: input.start, end: input.position, partial };\n}\n\n/** Whether `@` starts a new mention rather than appearing inside a token. */\nfunction isMentionBoundary(input: { beforeCursor: string; start: number }): boolean {\n const previous = input.start > 0 ? input.beforeCursor[input.start - 1] : \"\";\n return !previous || /\\s/.test(previous);\n}\n\n/** Normalize path separators in a partial mention path. */\nexport function normalizePartialPath(partial: string): string {\n return partial.replaceAll(\"\\\\\", \"/\").replaceAll(sep, \"/\");\n}\n\n/** Whether a partial mention path escapes the repo root. */\nexport function isUnsafePartial(partial: string): boolean {\n if (isAbsolute(partial) || partial.startsWith(\"/\")) return true;\n return partial.split(\"/\").filter(Boolean).includes(\"..\");\n}\n\n/** Sort directories before files, then lexicographically by path. */\nexport function compareCompletionMatches(\n left: FileCompletionMatch,\n right: FileCompletionMatch,\n): number {\n if (left.isDirectory !== right.isDirectory) return left.isDirectory ? -1 : 1;\n return left.path.localeCompare(right.path);\n}\n\n/** Replace the active mention span with the chosen completion path. */\nexport function applyFileCompletion(\n input: string,\n completion: { start: number; end: number; replacement: string },\n): string {\n return `${input.slice(0, completion.start + 1)}${completion.replacement}${input.slice(completion.end)}`;\n}\n","import { readdir } from \"node:fs/promises\";\nimport { ensureInsideRepo } from \"@/features/tools\";\nimport {\n compareCompletionMatches,\n findActiveFileMention,\n isUnsafePartial,\n normalizePartialPath,\n} from \"./fileAutocompleteHelpers.ts\";\nimport {\n DEFAULT_COMPLETION_LIMIT,\n type FileCompletionMatch,\n type FileCompletionOptions,\n type FileCompletionResult,\n IGNORED_COMPLETION_ENTRIES,\n} from \"./fileAutocompleteTypes.ts\";\n\n/** Complete an active `@file` mention against files inside the repo. */\nexport async function completeFileMention(\n input: string,\n repoRoot: string,\n options: FileCompletionOptions = {},\n): Promise<FileCompletionResult | null> {\n const active = findActiveFileMention(input);\n if (!active) return null;\n const partial = normalizePartialPath(active.partial);\n if (isUnsafePartial(partial)) return null;\n return buildFileCompletionResult({\n active,\n partial,\n repoRoot,\n limit: options.limit ?? DEFAULT_COMPLETION_LIMIT,\n });\n}\n\n/** Build a completion result when matches exist for a partial mention. */\nasync function buildFileCompletionResult(input: {\n active: NonNullable<ReturnType<typeof findActiveFileMention>>;\n partial: string;\n repoRoot: string;\n limit: number;\n}): Promise<FileCompletionResult | null> {\n const matches = await listCompletionMatches({\n partial: input.partial,\n repoRoot: input.repoRoot,\n limit: input.limit,\n });\n const best = matches[0];\n if (best === undefined) return null;\n return { ...input.active, partial: input.partial, replacement: best.path, matches };\n}\n\ninterface ListMatchesInput {\n partial: string;\n repoRoot: string;\n limit: number;\n}\n\nasync function listCompletionMatches(input: ListMatchesInput): Promise<FileCompletionMatch[]> {\n const parts = splitPartialPath(input.partial);\n const absoluteSearchDir = resolveCompletionSearchDir({\n dirPrefix: parts.dirPrefix,\n repoRoot: input.repoRoot,\n });\n if (!absoluteSearchDir) return [];\n return readCompletionMatches({ ...input, ...parts, absoluteSearchDir });\n}\n\n/** Split a partial mention path into directory and name prefixes. */\nfunction splitPartialPath(partial: string): { dirPrefix: string; namePrefix: string } {\n const lastSlashIndex = partial.lastIndexOf(\"/\");\n return {\n dirPrefix: lastSlashIndex === -1 ? \"\" : partial.slice(0, lastSlashIndex),\n namePrefix: lastSlashIndex === -1 ? partial : partial.slice(lastSlashIndex + 1),\n };\n}\n\n/** Resolve the absolute directory to search for completion matches. */\nfunction resolveCompletionSearchDir(input: { dirPrefix: string; repoRoot: string }): string | null {\n try {\n return ensureInsideRepo(input.dirPrefix || \".\", input.repoRoot);\n } catch {\n return null;\n }\n}\n\n/** Read and filter directory entries into completion matches. */\nasync function readCompletionMatches(\n input: ListMatchesInput & {\n dirPrefix: string;\n namePrefix: string;\n absoluteSearchDir: string;\n },\n): Promise<FileCompletionMatch[]> {\n try {\n const dirents = await readdir(input.absoluteSearchDir, { withFileTypes: true });\n return dirents\n .filter((dirent) => dirent.isDirectory() || dirent.isFile())\n .filter((dirent) => !IGNORED_COMPLETION_ENTRIES.has(dirent.name))\n .filter((dirent) => input.namePrefix.startsWith(\".\") || !dirent.name.startsWith(\".\"))\n .filter((dirent) => dirent.name.startsWith(input.namePrefix))\n .map((dirent) => mapDirent({ dirent, dirPrefix: input.dirPrefix }))\n .sort((...args: [FileCompletionMatch, FileCompletionMatch]) =>\n compareCompletionMatches(args[0], args[1]),\n )\n .slice(0, input.limit);\n } catch {\n return [];\n }\n}\n\nfunction mapDirent(input: {\n dirent: { name: string; isDirectory(): boolean };\n dirPrefix: string;\n}): FileCompletionMatch {\n const path = input.dirPrefix ? `${input.dirPrefix}/${input.dirent.name}` : input.dirent.name;\n return {\n path: input.dirent.isDirectory() ? `${path}/` : path,\n isDirectory: input.dirent.isDirectory(),\n };\n}\n","/** Active `@file` mention span inside composer input text. */\nexport interface ActiveFileMention {\n /** Start index of the `@` character. */\n start: number;\n /** End index of the active mention span. */\n end: number;\n /** Partial path typed after `@`. */\n partial: string;\n}\n\n/** One filesystem entry offered as a completion candidate. */\nexport interface FileCompletionMatch {\n /** Repo-relative path with trailing slash for directories. */\n path: string;\n /** Whether the entry is a directory. */\n isDirectory: boolean;\n}\n\n/** Result of completing an active `@file` mention. */\nexport interface FileCompletionResult extends ActiveFileMention {\n /** Normalized partial path used for matching. */\n partial: string;\n /** Best-match replacement path. */\n replacement: string;\n /** All completion candidates within the limit. */\n matches: FileCompletionMatch[];\n}\n\n/** Options controlling file mention completion behavior. */\nexport interface FileCompletionOptions {\n /** Maximum number of matches to return. */\n limit?: number;\n}\n\n/** Default maximum number of completion matches. */\nexport const DEFAULT_COMPLETION_LIMIT = 20;\n\n/** Directory names excluded from file mention completion. */\nexport const IGNORED_COMPLETION_ENTRIES = new Set([\n \".git\",\n \"node_modules\",\n \"dist\",\n \"build\",\n \"coverage\",\n \".next\",\n \".turbo\",\n]);\n","/** Kind of autocomplete item shown in the composer assist panel. */\nexport type SuggestionKind =\n | \"command\"\n | \"file\"\n | \"folder\"\n | \"mode\"\n | \"session\"\n | \"checkpoint\"\n | \"model\"\n | \"scope\"\n | \"flag\"\n | \"url\"\n | \"text\";\n\n/** One autocomplete candidate for the composer input. */\nexport interface InputSuggestion {\n value: string;\n label: string;\n kind: SuggestionKind;\n detail?: string;\n}\n\n/** Group of related autocomplete candidates with replacement range metadata. */\nexport interface InputSuggestionGroup {\n title: string;\n hint?: string;\n replacementStart?: number;\n replacementEnd?: number;\n suggestions: InputSuggestion[];\n}\n\n/** Inputs for loading autocomplete suggestions for the current input. */\nexport interface LoadInputSuggestionsOptions {\n repoRoot: string;\n commands: readonly import(\"../../../domain/types.ts\").CommandDef[];\n limit?: number;\n sessionOptions?: import(\"../../../store/sessionStore.ts\").SessionStoreOptions;\n checkpointRoot?: string;\n customCommandsHomeDir?: string;\n}\n\n/** Parsed slash-command input with command name and trailing args. */\nexport interface ParsedSlashInput {\n command: string;\n args: string;\n argsStart: number;\n}\n\n/** Rule metadata for slash-command argument suggestions. */\nexport interface CommandSuggestionRule {\n title: string;\n hint: string;\n values?: readonly InputSuggestion[];\n}\n\n/** Active argument token within a slash command's args string. */\nexport interface ActiveArgumentToken {\n start: number;\n end: number;\n value: string;\n}\n\nexport const DEFAULT_SUGGESTION_LIMIT = 8;\n","import { COMMAND_SUGGESTION_RULES } from \"./commandRules.ts\";\nimport type { InputSuggestion, InputSuggestionGroup } from \"./types.ts\";\nimport { DEFAULT_SUGGESTION_LIMIT } from \"./types.ts\";\n\n/** Inputs for filtering suggestions by query prefix. */\ninterface WithFilteredSuggestionsParams {\n group: InputSuggestionGroup;\n suggestions: readonly InputSuggestion[];\n query: string;\n limit?: number;\n}\n\n/** Filter suggestions by query and apply the limit. */\nexport function withFilteredSuggestions(\n params: WithFilteredSuggestionsParams,\n): InputSuggestionGroup {\n const normalizedQuery = params.query.toLowerCase();\n const limit = params.limit ?? DEFAULT_SUGGESTION_LIMIT;\n return {\n ...params.group,\n suggestions: params.suggestions\n .filter((suggestion) => suggestion.value.toLowerCase().includes(normalizedQuery))\n .slice(0, limit),\n };\n}\n\n/** Apply a selected suggestion to the input string. */\nexport function applyInputSuggestion(\n input: string,\n group: InputSuggestionGroup,\n index = 0,\n): string {\n const suggestion = group.suggestions[index];\n if (!suggestion || group.replacementStart === undefined || group.replacementEnd === undefined)\n return input;\n return `${input.slice(0, group.replacementStart)}${suggestion.value}${input.slice(group.replacementEnd)}`;\n}\n\n/** List built-in commands missing a suggestion rule entry. */\nexport function commandSuggestionCoverage(commands: readonly { name: string }[]): string[] {\n return commands.map((command) => command.name).filter((name) => !COMMAND_SUGGESTION_RULES[name]);\n}\n","import type { ActiveArgumentToken, ParsedSlashInput } from \"./types.ts\";\n\n/** Parse a slash-command input string into command name and args. */\nexport function parseSlashInput(input: string): ParsedSlashInput | null {\n if (!input.startsWith(\"/\")) return null;\n const spaceIndex = input.indexOf(\" \");\n if (spaceIndex === -1) return { command: input.slice(1), args: \"\", argsStart: input.length };\n return {\n command: input.slice(1, spaceIndex),\n args: input.slice(spaceIndex + 1),\n argsStart: spaceIndex + 1,\n };\n}\n\n/** Extract the active argument token at the end of slash command args. */\nexport function activeArgumentToken(slash: ParsedSlashInput): ActiveArgumentToken {\n const beforeCursor = slash.args;\n const match = /(?:^|\\s)(\\S*)$/.exec(beforeCursor);\n const value = match?.[1] ?? \"\";\n const start = slash.argsStart + beforeCursor.length - value.length;\n return { start, end: slash.argsStart + beforeCursor.length, value };\n}\n\n/** Split slash command args on whitespace. */\nexport function splitArgs(input: string): string[] {\n return input.trim().split(/\\s+/).filter(Boolean);\n}\n\n/** Whether the args string ends with trailing whitespace. */\nexport function hasTrailingWhitespace(input: string): boolean {\n return /\\s$/.test(input);\n}\n","import { readdir } from \"node:fs/promises\";\nimport { extname, sep } from \"node:path\";\nimport { ensureInsideRepo } from \"@/features/tools\";\nimport { comparePathSuggestions, entryToSuggestion } from \"./pathSuggestionUtils.ts\";\nimport type { InputSuggestion } from \"./types.ts\";\n\nconst IGNORED_COMPLETION_ENTRIES = new Set([\n \".git\",\n \"node_modules\",\n \"dist\",\n \"build\",\n \"coverage\",\n \".next\",\n \".turbo\",\n]);\nconst IMAGE_EXTENSIONS = new Set([\".png\", \".jpg\", \".jpeg\", \".webp\", \".gif\"]);\n\n/** Inputs for listing repo path suggestions. */\nexport interface RepoPathSuggestionsParams {\n repoRoot: string;\n partial: string;\n kind: \"all\" | \"image\";\n limit: number;\n}\n\n/** List file and folder path suggestions under the repo root. */\nexport async function repoPathSuggestions(\n params: RepoPathSuggestionsParams,\n): Promise<InputSuggestion[]> {\n const parts = parsePartialPath(params.partial);\n if (!parts) return [];\n const absoluteSearchDir = resolveSearchDir({\n dirPrefix: parts.dirPrefix,\n repoRoot: params.repoRoot,\n });\n if (!absoluteSearchDir) return [];\n return listMatchingEntries({ ...params, ...parts, absoluteSearchDir });\n}\n\n/** Parsed partial path components for repo completion. */\ninterface PartialPathParts {\n dirPrefix: string;\n namePrefix: string;\n}\n\n/** Parse a partial path into directory prefix and name prefix. */\nfunction parsePartialPath(partial: string): PartialPathParts | null {\n const normalized = partial.replaceAll(\"\\\\\", \"/\").replaceAll(sep, \"/\");\n if (normalized.startsWith(\"/\") || normalized.split(\"/\").includes(\"..\")) return null;\n const slashIndex = normalized.lastIndexOf(\"/\");\n return {\n dirPrefix: slashIndex === -1 ? \"\" : normalized.slice(0, slashIndex),\n namePrefix: slashIndex === -1 ? normalized : normalized.slice(slashIndex + 1),\n };\n}\n\n/** Resolve the absolute search directory inside the repo. */\nfunction resolveSearchDir(input: { dirPrefix: string; repoRoot: string }): string | null {\n try {\n return ensureInsideRepo(input.dirPrefix || \".\", input.repoRoot);\n } catch {\n return null;\n }\n}\n\n/** Inputs for listing directory entries matching a name prefix. */\ninterface ListMatchingEntriesParams extends RepoPathSuggestionsParams, PartialPathParts {\n absoluteSearchDir: string;\n}\n\n/** Read directory entries and map them to path suggestions. */\nasync function listMatchingEntries(params: ListMatchingEntriesParams): Promise<InputSuggestion[]> {\n try {\n const entries = await readdir(params.absoluteSearchDir, { withFileTypes: true });\n return entries\n .filter((entry) => isCompletableEntry({ name: entry.name, namePrefix: params.namePrefix }))\n .filter((entry) => matchesKind({ entry, kind: params.kind, namePrefix: params.namePrefix }))\n .map((entry) => entryToSuggestion(entry.name, params.dirPrefix, entry.isDirectory()))\n .sort((...args: [InputSuggestion, InputSuggestion]) =>\n comparePathSuggestions(args[0], args[1]),\n )\n .slice(0, params.limit);\n } catch {\n return [];\n }\n}\n\n/** Whether a directory entry should appear in completion results. */\nfunction isCompletableEntry(input: { name: string; namePrefix: string }): boolean {\n if (IGNORED_COMPLETION_ENTRIES.has(input.name)) return false;\n return input.namePrefix.startsWith(\".\") || !input.name.startsWith(\".\");\n}\n\n/** Whether an entry matches the requested kind and name prefix. */\nfunction matchesKind(input: {\n entry: { name: string; isDirectory(): boolean; isFile(): boolean };\n kind: \"all\" | \"image\";\n namePrefix: string;\n}): boolean {\n if (!input.entry.isDirectory() && !input.entry.isFile()) return false;\n if (!input.entry.name.startsWith(input.namePrefix)) return false;\n if (input.entry.isDirectory()) return true;\n return input.kind === \"all\" || IMAGE_EXTENSIONS.has(extname(input.entry.name).toLowerCase());\n}\n","import type { InputSuggestion } from \"./types.ts\";\n\n/** Map one directory entry to an InputSuggestion. */\nexport function entryToSuggestion(\n name: string,\n dirPrefix: string,\n isDirectory: boolean,\n): InputSuggestion {\n const path = dirPrefix ? `${dirPrefix}/${name}` : name;\n const value = isDirectory ? `${path}/` : path;\n return {\n value,\n label: value,\n kind: isDirectory ? \"folder\" : \"file\",\n detail: isDirectory ? \"folder\" : undefined,\n };\n}\n\n/** Sort folders before files, then alphabetically by label. */\nexport function comparePathSuggestions(left: InputSuggestion, right: InputSuggestion): number {\n if (left.kind !== right.kind) {\n if (left.kind === \"folder\") return -1;\n if (right.kind === \"folder\") return 1;\n }\n return left.label.localeCompare(right.label);\n}\n","import { repoPathSuggestions } from \"./repoPathSuggestions.ts\";\nimport type { InputSuggestionGroup, LoadInputSuggestionsOptions } from \"./types.ts\";\nimport { DEFAULT_SUGGESTION_LIMIT } from \"./types.ts\";\n\n/** Inputs for building a path suggestion group. */\ninterface PathSuggestionGroupParams {\n base: InputSuggestionGroup;\n partial: string;\n options: LoadInputSuggestionsOptions;\n kind: \"all\" | \"image\";\n}\n\n/** Build a suggestion group for repo path completion. */\nexport async function pathSuggestionGroup(\n params: PathSuggestionGroupParams,\n): Promise<InputSuggestionGroup> {\n const limit = params.options.limit ?? DEFAULT_SUGGESTION_LIMIT;\n const matches = await repoPathSuggestions({\n repoRoot: params.options.repoRoot,\n partial: params.partial,\n kind: params.kind,\n limit,\n });\n return {\n ...params.base,\n suggestions: matches,\n hint:\n matches.length > 0 ? \"Tab inserts the first path. Directories end with /.\" : params.base.hint,\n };\n}\n","import { listModelProfiles } from \"@/features/domain\";\nimport { listCheckpoints } from \"@/features/store\";\nimport { sessionsDir } from \"@/features/store\";\nimport { listSessions } from \"@/features/store\";\nimport type { InputSuggestion, LoadInputSuggestionsOptions } from \"./types.ts\";\nimport { DEFAULT_SUGGESTION_LIMIT } from \"./types.ts\";\n\n/** List recent local bridge sessions as suggestions. */\nexport async function sessionSuggestions(\n options: LoadInputSuggestionsOptions,\n): Promise<InputSuggestion[]> {\n const sessions = await listSessions(\n options.sessionOptions ?? { baseDir: sessionsDir(options.repoRoot) },\n );\n return sessions.slice(0, options.limit ?? DEFAULT_SUGGESTION_LIMIT).map((session) => ({\n value: session.id,\n label: session.id,\n kind: \"session\" as const,\n detail: `${session.updatedAt} ${session.model ?? \"unknown\"}`,\n }));\n}\n\n/** List recent file checkpoints as suggestions. */\nexport async function checkpointSuggestions(\n options: LoadInputSuggestionsOptions,\n): Promise<InputSuggestion[]> {\n const checkpoints = await listCheckpoints({\n repoRoot: options.repoRoot,\n checkpointRoot: options.checkpointRoot,\n });\n return checkpoints.slice(0, options.limit ?? DEFAULT_SUGGESTION_LIMIT).map((checkpoint) => ({\n value: checkpoint.id,\n label: checkpoint.id,\n kind: \"checkpoint\" as const,\n detail: `${checkpoint.phase} ${checkpoint.fileCount} files ${checkpoint.label ?? \"\"}`.trim(),\n }));\n}\n\n/** List known model profiles as suggestions. */\nexport function modelSuggestions(options: LoadInputSuggestionsOptions): InputSuggestion[] {\n return listModelProfiles().map((profile) => ({\n value: profile.label,\n label: profile.label,\n kind: \"model\" as const,\n detail: `${profile.contextWindow.toLocaleString()} ctx`,\n }));\n}\n\n/** Resume/open command flag and session suggestions. */\nexport async function resumeSessionSuggestions(\n options: LoadInputSuggestionsOptions,\n): Promise<InputSuggestion[]> {\n return [\n { value: \"--last\", label: \"--last\", kind: \"flag\", detail: \"latest local bridge session\" },\n ...(await sessionSuggestions(options)),\n ];\n}\n\n/** Rewind flag suggestions for --files and --both. */\nexport function rewindFlagSuggestions(): InputSuggestion[] {\n return [\n { value: \"--files\", label: \"--files\", kind: \"flag\", detail: \"restore files only\" },\n { value: \"--both\", label: \"--both\", kind: \"flag\", detail: \"restore files and retry prompt\" },\n ];\n}\n","import { withFilteredSuggestions } from \"./filterSuggestions.ts\";\nimport { type activeArgumentToken, hasTrailingWhitespace, splitArgs } from \"./parseSlashInput.ts\";\nimport { pathSuggestionGroup } from \"./pathSuggestions.ts\";\nimport {\n checkpointSuggestions,\n rewindFlagSuggestions,\n sessionSuggestions,\n} from \"./sessionCheckpointSuggestions.ts\";\nimport type {\n InputSuggestionGroup,\n LoadInputSuggestionsOptions,\n ParsedSlashInput,\n} from \"./types.ts\";\n\n/** Inputs for export/restore/rewind argument suggestion handlers. */\ninterface CommandArgHandlerParams {\n slash: ParsedSlashInput;\n options: LoadInputSuggestionsOptions;\n base: InputSuggestionGroup;\n token: ReturnType<typeof activeArgumentToken>;\n}\n\n/** Suggest session ids or output path hint for /export. */\nexport async function exportArgumentSuggestions(\n params: CommandArgHandlerParams,\n): Promise<InputSuggestionGroup> {\n const tokens = splitArgs(params.slash.args);\n if (tokens.length === 0 || (tokens.length === 1 && !hasTrailingWhitespace(params.slash.args))) {\n return withFilteredSuggestions({\n group: params.base,\n suggestions: await sessionSuggestions(params.options),\n query: params.token.value,\n limit: params.options.limit,\n });\n }\n return {\n ...params.base,\n hint: \"Type the export output path. Supported extensions: .md, .json, .jsonl.\",\n };\n}\n\n/** Suggest checkpoint ids or repo paths for /restore. */\nexport async function restoreArgumentSuggestions(\n params: CommandArgHandlerParams,\n): Promise<InputSuggestionGroup> {\n const tokens = splitArgs(params.slash.args);\n if (tokens.length === 0 || (tokens.length === 1 && !hasTrailingWhitespace(params.slash.args))) {\n return withFilteredSuggestions({\n group: params.base,\n suggestions: await checkpointSuggestions(params.options),\n query: params.token.value,\n limit: params.options.limit,\n });\n }\n return pathSuggestionGroup({\n base: params.base,\n partial: params.token.value,\n options: params.options,\n kind: \"all\",\n });\n}\n\n/** Suggest rewind flags or checkpoint ids for /rewind and /retry. */\nexport async function rewindArgumentSuggestions(\n params: CommandArgHandlerParams,\n): Promise<InputSuggestionGroup> {\n const tokens = splitArgs(params.slash.args);\n const firstToken = tokens[0];\n if (shouldSuggestCheckpoints({ tokens, args: params.slash.args, firstToken })) {\n return checkpointFilteredSuggestions(params);\n }\n return resolveRewindArgumentSuggestions({ params, tokens, firstToken });\n}\n\n/** Resolve rewind suggestions after checkpoint filtering is ruled out. */\nasync function resolveRewindArgumentSuggestions(input: {\n params: CommandArgHandlerParams;\n tokens: string[];\n firstToken: string | undefined;\n}): Promise<InputSuggestionGroup> {\n if (input.tokens.length <= 1) return rewindFlagSuggestionGroup(input.params);\n if (input.firstToken === \"--files\" || input.firstToken === \"--both\")\n return checkpointFilteredSuggestions(input.params);\n return input.params.base;\n}\n\n/** Suggest rewind mode flags for the first argument token. */\nfunction rewindFlagSuggestionGroup(params: CommandArgHandlerParams): InputSuggestionGroup {\n return withFilteredSuggestions({\n group: params.base,\n suggestions: rewindFlagSuggestions(),\n query: params.token.value,\n limit: params.options.limit,\n });\n}\n\n/** Whether rewind args should show checkpoint suggestions. */\nfunction shouldSuggestCheckpoints(input: {\n tokens: string[];\n args: string;\n firstToken: string | undefined;\n}): boolean {\n return (\n (input.firstToken === \"--files\" || input.firstToken === \"--both\") &&\n (input.tokens.length > 1 || hasTrailingWhitespace(input.args))\n );\n}\n\n/** Filter checkpoint suggestions for rewind restore steps. */\nasync function checkpointFilteredSuggestions(\n params: CommandArgHandlerParams,\n): Promise<InputSuggestionGroup> {\n return withFilteredSuggestions({\n group: params.base,\n suggestions: await checkpointSuggestions(params.options),\n query: params.token.value,\n limit: params.options.limit,\n });\n}\n","import {\n exportArgumentSuggestions,\n restoreArgumentSuggestions,\n rewindArgumentSuggestions,\n} from \"./commandArgHandlers.ts\";\nimport { COMMAND_SUGGESTION_RULES } from \"./commandRules.ts\";\nimport { withFilteredSuggestions } from \"./filterSuggestions.ts\";\nimport { activeArgumentToken } from \"./parseSlashInput.ts\";\nimport { pathSuggestionGroup } from \"./pathSuggestions.ts\";\nimport {\n modelSuggestions,\n resumeSessionSuggestions,\n sessionSuggestions,\n} from \"./sessionCheckpointSuggestions.ts\";\nimport type {\n InputSuggestionGroup,\n LoadInputSuggestionsOptions,\n ParsedSlashInput,\n} from \"./types.ts\";\n\n/** Build autocomplete suggestions for slash command arguments. */\nexport async function commandArgumentSuggestions(\n slash: ParsedSlashInput,\n options: LoadInputSuggestionsOptions,\n): Promise<InputSuggestionGroup | null> {\n const rule = COMMAND_SUGGESTION_RULES[slash.command] ?? {\n title: `/${slash.command}`,\n hint: \"Type arguments for this command. Use @ to mention repo files.\",\n };\n const token = activeArgumentToken(slash);\n const base: InputSuggestionGroup = {\n title: rule.title,\n hint: rule.hint,\n replacementStart: token.start,\n replacementEnd: token.end,\n suggestions: [],\n };\n return dispatchCommandArgumentSuggestions({ slash, options, rule, base, token });\n}\n\n/** Inputs for dispatching command-specific argument suggestions. */\ninterface DispatchCommandArgumentSuggestionsParams {\n slash: ParsedSlashInput;\n options: LoadInputSuggestionsOptions;\n rule: { title: string; hint: string; values?: readonly import(\"./types.ts\").InputSuggestion[] };\n base: InputSuggestionGroup;\n token: ReturnType<typeof activeArgumentToken>;\n}\n\n/** Route to the handler for the active slash command's arguments. */\nasync function dispatchCommandArgumentSuggestions(\n params: DispatchCommandArgumentSuggestionsParams,\n): Promise<InputSuggestionGroup | null> {\n const handler = COMMAND_ARG_HANDLERS[params.slash.command];\n if (handler) return handler(params);\n return withFilteredSuggestions({\n group: params.base,\n suggestions: params.rule.values ?? [],\n query: params.token.value,\n limit: params.options.limit,\n });\n}\n\n/** Per-command argument suggestion handlers. */\nconst COMMAND_ARG_HANDLERS: Record<\n string,\n (params: DispatchCommandArgumentSuggestionsParams) => Promise<InputSuggestionGroup | null>\n> = {\n resume: (p) => filteredResumeSuggestions(p),\n open: (p) => filteredResumeSuggestions(p),\n transcript: (p) => filteredSessionSuggestions(p),\n copy: (p) => filteredSessionSuggestions(p),\n export: (p) =>\n exportArgumentSuggestions({ slash: p.slash, options: p.options, base: p.base, token: p.token }),\n permissions: (p) =>\n Promise.resolve(\n withFilteredSuggestions({\n group: p.base,\n suggestions: p.rule.values ?? [],\n query: p.token.value,\n limit: p.options.limit,\n }),\n ),\n model: (p) =>\n Promise.resolve(\n withFilteredSuggestions({\n group: p.base,\n suggestions: modelSuggestions(p.options),\n query: p.token.value,\n limit: p.options.limit,\n }),\n ),\n restore: (p) =>\n restoreArgumentSuggestions({\n slash: p.slash,\n options: p.options,\n base: p.base,\n token: p.token,\n }),\n rewind: (p) =>\n rewindArgumentSuggestions({ slash: p.slash, options: p.options, base: p.base, token: p.token }),\n retry: (p) =>\n rewindArgumentSuggestions({ slash: p.slash, options: p.options, base: p.base, token: p.token }),\n review: (p) =>\n Promise.resolve(\n withFilteredSuggestions({\n group: p.base,\n suggestions: p.rule.values ?? [],\n query: p.token.value,\n limit: p.options.limit,\n }),\n ),\n \"attach-image\": (p) =>\n pathSuggestionGroup({\n base: p.base,\n partial: p.token.value,\n options: p.options,\n kind: \"image\",\n }),\n screenshot: (p) =>\n Promise.resolve(\n withFilteredSuggestions({\n group: p.base,\n suggestions: p.rule.values ?? [],\n query: p.token.value,\n limit: p.options.limit,\n }),\n ),\n \"ui-qa\": (p) =>\n Promise.resolve(\n withFilteredSuggestions({\n group: p.base,\n suggestions: p.rule.values ?? [],\n query: p.token.value,\n limit: p.options.limit,\n }),\n ),\n task: (p) =>\n Promise.resolve({\n ...p.base,\n replacementStart: undefined,\n replacementEnd: undefined,\n hint: \"Describe the coding task. Type @ to see repo files and folders.\",\n }),\n work: (p) =>\n Promise.resolve({\n ...p.base,\n replacementStart: undefined,\n replacementEnd: undefined,\n hint: \"Describe the coding task. Type @ to see repo files and folders.\",\n }),\n};\n\n/** Filter resume/open session suggestions. */\nasync function filteredResumeSuggestions(\n params: DispatchCommandArgumentSuggestionsParams,\n): Promise<InputSuggestionGroup> {\n return withFilteredSuggestions({\n group: params.base,\n suggestions: await resumeSessionSuggestions(params.options),\n query: params.token.value,\n limit: params.options.limit,\n });\n}\n\n/** Filter transcript/copy session suggestions. */\nasync function filteredSessionSuggestions(\n params: DispatchCommandArgumentSuggestionsParams,\n): Promise<InputSuggestionGroup> {\n return withFilteredSuggestions({\n group: params.base,\n suggestions: await sessionSuggestions(params.options),\n query: params.token.value,\n limit: params.options.limit,\n });\n}\n","import type { CommandDef } from \"@/features/domain\";\nimport { loadCustomCommands } from \"@/features/user-config\";\nimport type {\n InputSuggestion,\n InputSuggestionGroup,\n LoadInputSuggestionsOptions,\n} from \"./types.ts\";\nimport { DEFAULT_SUGGESTION_LIMIT } from \"./types.ts\";\n\n/** Inputs for building slash command name suggestions. */\ninterface CommandNameSuggestionsParams {\n partial: string;\n commands: readonly CommandDef[];\n options: LoadInputSuggestionsOptions;\n}\n\n/** Build autocomplete suggestions for an in-progress slash command name. */\nexport async function commandNameSuggestions(\n params: CommandNameSuggestionsParams,\n): Promise<InputSuggestionGroup | null> {\n const custom = await loadCustomCommands({\n repoRoot: params.options.repoRoot,\n homeDir: params.options.customCommandsHomeDir,\n });\n const suggestions = buildCommandNameSuggestions({ params, custom });\n return {\n title: \"Commands\",\n hint: \"Tab inserts the first command. Enter runs the selected command.\",\n replacementStart: 0,\n replacementEnd: params.partial.length + 1,\n suggestions,\n };\n}\n\n/** Merge built-in and custom command suggestions filtered by partial input. */\nfunction buildCommandNameSuggestions(input: {\n params: CommandNameSuggestionsParams;\n custom: Awaited<ReturnType<typeof loadCustomCommands>>;\n}): InputSuggestion[] {\n const builtIns = input.params.commands.map((command) => ({\n value: `/${command.name} `,\n label: `/${command.name}`,\n kind: \"command\" as const,\n detail: command.description,\n }));\n const customSuggestions = input.custom.map((command) => ({\n value: `/${command.name} `,\n label: `/${command.name}`,\n kind: \"command\" as const,\n detail: command.description ?? `${command.source} custom command`,\n }));\n const query = input.params.partial.toLowerCase();\n return [...builtIns, ...customSuggestions]\n .filter((suggestion) => suggestion.label.slice(1).toLowerCase().startsWith(query))\n .slice(0, input.params.options.limit ?? DEFAULT_SUGGESTION_LIMIT);\n}\n","import { completeFileMention } from \"../fileAutocomplete.ts\";\nimport { commandArgumentSuggestions } from \"./commandArgumentSuggestions.ts\";\nimport { commandNameSuggestions } from \"./commandNameSuggestions.ts\";\nimport { parseSlashInput } from \"./parseSlashInput.ts\";\nimport type { InputSuggestionGroup, LoadInputSuggestionsOptions } from \"./types.ts\";\nimport { DEFAULT_SUGGESTION_LIMIT } from \"./types.ts\";\n\n/** Load autocomplete suggestions for the current composer input. */\nexport async function loadInputSuggestions(\n input: string,\n options: LoadInputSuggestionsOptions,\n): Promise<InputSuggestionGroup | null> {\n const limit = options.limit ?? DEFAULT_SUGGESTION_LIMIT;\n const fileMention = await completeFileMention(input, options.repoRoot, { limit });\n if (fileMention) return fileMentionSuggestionGroup({ input, fileMention });\n return loadSlashSuggestions({ input, options });\n}\n\n/** Load slash command name or argument suggestions. */\nasync function loadSlashSuggestions(input: {\n input: string;\n options: LoadInputSuggestionsOptions;\n}): Promise<InputSuggestionGroup | null> {\n const slash = parseSlashInput(input.input);\n if (!slash) return null;\n if (!input.input.includes(\" \")) {\n return commandNameSuggestions({\n partial: slash.command,\n commands: input.options.commands,\n options: input.options,\n });\n }\n return commandArgumentSuggestions(slash, input.options);\n}\n\n/** Inputs for mapping file mention matches to a suggestion group. */\ninterface FileMentionMatch {\n start: number;\n end: number;\n matches: Array<{ path: string; isDirectory: boolean }>;\n}\n\n/** Build a suggestion group from active @ file mention matches. */\nfunction fileMentionSuggestionGroup(input: {\n input: string;\n fileMention: FileMentionMatch;\n}): InputSuggestionGroup {\n return {\n title: \"Files and folders\",\n hint: \"Tab inserts the first match. Continue typing to narrow.\",\n replacementStart: input.fileMention.start,\n replacementEnd: input.fileMention.end,\n suggestions: input.fileMention.matches.map((match) => ({\n value: `@${match.path}`,\n label: `@${match.path}`,\n kind: match.isDirectory ? (\"folder\" as const) : (\"file\" as const),\n })),\n };\n}\n","import type { CommandDef } from \"@/features/domain\";\nimport type { ComposerKeyboardOptions } from \"./composerKeyboardTypes.ts\";\nimport { type InputSuggestionGroup, applyInputSuggestion } from \"./inputSuggestions.ts\";\nimport type { ComposerState } from \"./useComposerState.ts\";\n\nexport function handleCommandListKeys(\n options: ComposerKeyboardOptions & {\n char: string;\n key: { upArrow?: boolean; downArrow?: boolean; tab?: boolean; return?: boolean };\n },\n) {\n const suggestions = options.state.inputSuggestions?.suggestions ?? [];\n if (options.key.upArrow) return moveCommandSelectionUp(options.state);\n if (options.key.downArrow) {\n return moveCommandSelectionDown({\n state: options.state,\n suggestions,\n matches: options.state.matches,\n });\n }\n if (options.key.tab) return completeCommandTab(options);\n return options.key.return ? submitCommandSelection({ options, suggestions }) : false;\n}\n\nfunction moveCommandSelectionUp(state: ComposerState) {\n state.setSelectedIdx((index) => Math.max(0, index - 1));\n return true;\n}\n\nfunction moveCommandSelectionDown(input: {\n state: ComposerState;\n suggestions: InputSuggestionGroup[\"suggestions\"];\n matches: readonly CommandDef[];\n}) {\n const maxIndex = Math.max(0, (input.suggestions.length || input.matches.length) - 1);\n input.state.setSelectedIdx((index) => Math.min(maxIndex, index + 1));\n return true;\n}\n\nfunction completeCommandTab(options: ComposerKeyboardOptions) {\n const suggestions = options.state.inputSuggestions?.suggestions ?? [];\n if (suggestions.length) completeSuggestionTab({ state: options.state, suggestions });\n else options.tabComplete();\n return true;\n}\n\nfunction completeSuggestionTab(input: {\n state: ComposerState;\n suggestions: InputSuggestionGroup[\"suggestions\"];\n}) {\n const suggestionIndex = Math.min(input.state.selectedIdx, input.suggestions.length - 1);\n const suggestion = input.suggestions[suggestionIndex] ?? input.suggestions[0];\n if (!suggestion) return;\n applySuggestionSelection({ state: input.state, suggestionIndex, label: suggestion.label });\n}\n\n/** Apply one selected suggestion to the composer input. */\nfunction applySuggestionSelection(input: {\n state: ComposerState;\n suggestionIndex: number;\n label: string;\n}): void {\n const suggestions = input.state.inputSuggestions;\n if (!suggestions) return;\n const nextInput = applyInputSuggestion(input.state.input, suggestions, input.suggestionIndex);\n input.state.setInput(nextInput);\n input.state.setMode(\"typing\");\n input.state.setStatus(`Completed ${input.label}`);\n}\n\nfunction submitCommandSelection(input: {\n options: ComposerKeyboardOptions;\n suggestions: InputSuggestionGroup[\"suggestions\"];\n}): boolean {\n if (input.suggestions.length > 0) return submitSuggestionCommand(input);\n if (input.options.state.matches.length > 0) return submitMatchedCommand(input.options);\n return false;\n}\n\nfunction submitSuggestionCommand(input: {\n options: ComposerKeyboardOptions;\n suggestions: InputSuggestionGroup[\"suggestions\"];\n}) {\n const suggestion = input.suggestions[input.options.state.selectedIdx] ?? input.suggestions[0];\n if (!suggestion) return false;\n resetCommandInput(input.options.state);\n void input.options.runCommand(suggestion.label);\n return true;\n}\n\nfunction submitMatchedCommand(options: ComposerKeyboardOptions) {\n const cmd = options.state.matches[options.state.selectedIdx] ?? options.state.matches[0];\n if (!cmd) return false;\n resetCommandInput(options.state);\n void options.runCommand(`/${cmd.name}`);\n return true;\n}\n\n/** Clear composer input after choosing a command from the menu. */\nfunction resetCommandInput(state: ComposerState): void {\n state.refs.suppressNextSubmit.current = true;\n state.setInput(\"\");\n state.setMode(\"typing\");\n}\n","const CTRL_R = \"\\u0012\";\n\ninterface PromptHistoryOptions {\n limit?: number;\n}\n\nconst DEFAULT_HISTORY_LIMIT = 100;\n\n/** Prompt history store with shell-style older/newer draft navigation. */\nexport class PromptHistory {\n private readonly limit: number;\n private readonly prompts: string[];\n private browseIndex: number | null = null;\n private draft = \"\";\n\n constructor(initialEntries: string[] = [], options: PromptHistoryOptions = {}) {\n this.limit = options.limit ?? DEFAULT_HISTORY_LIMIT;\n this.prompts = [];\n for (const entry of initialEntries) this.add(entry);\n }\n\n /** Record a prompt, skipping empties and consecutive duplicates. */\n add(prompt: string): void {\n const trimmed = prompt.trim();\n if (!this.shouldStorePrompt(trimmed)) return;\n this.prompts.push(trimmed);\n this.trimToLimit();\n this.resetBrowsing();\n }\n\n /** Skip empty or duplicate consecutive prompts. */\n private shouldStorePrompt(trimmed: string): boolean {\n if (!trimmed) return false;\n return this.prompts.at(-1) !== trimmed;\n }\n\n /** Drop oldest entries when history exceeds the limit. */\n private trimToLimit(): void {\n while (this.prompts.length > this.limit) this.prompts.shift();\n }\n\n /** Snapshot of stored prompts, oldest first. */\n entries(): string[] {\n return [...this.prompts];\n }\n\n /** Step to the older prompt, stashing the live draft on the first step back. */\n previous(currentDraft: string): string {\n if (this.prompts.length === 0) return currentDraft;\n if (this.browseIndex === null) {\n this.draft = currentDraft;\n this.browseIndex = this.prompts.length - 1;\n } else {\n this.browseIndex = Math.max(0, this.browseIndex - 1);\n }\n return this.prompts[this.browseIndex] ?? currentDraft;\n }\n\n /** Step toward newer prompts, returning to the stashed draft past the newest. */\n next(): string {\n if (this.browseIndex === null) return \"\";\n if (this.browseIndex >= this.prompts.length) return this.draft;\n if (this.browseIndex < this.prompts.length - 1) {\n this.browseIndex += 1;\n return this.prompts[this.browseIndex] ?? this.draft;\n }\n this.browseIndex = this.prompts.length;\n return this.draft;\n }\n\n /** Exit history browsing and clear the stashed draft. */\n resetBrowsing(): void {\n this.browseIndex = null;\n this.draft = \"\";\n }\n}\n\nexport function createPromptHistory(options: PromptHistoryOptions = {}): PromptHistory {\n return new PromptHistory([], options);\n}\n\nexport function getReverseSearchQuery(input: string): string | null {\n const markerIndex = input.lastIndexOf(CTRL_R);\n if (markerIndex === -1) return null;\n return input.slice(markerIndex + CTRL_R.length);\n}\n\nexport function findReverseHistoryMatch(entries: string[], query: string): string | null {\n const normalizedQuery = query.toLowerCase();\n for (let i = entries.length - 1; i >= 0; i -= 1) {\n const entry = entries[i];\n if (entry === undefined) continue;\n if (normalizedQuery === \"\" || entry.toLowerCase().includes(normalizedQuery)) return entry;\n }\n return null;\n}\n","import { findReverseHistoryMatch } from \"./composerHistory.ts\";\nimport type { ComposerKeyboardOptions } from \"./composerKeyboardTypes.ts\";\nimport { applyInputSuggestion } from \"./inputSuggestions.ts\";\nimport type { ComposerState } from \"./useComposerState.ts\";\n\nexport function handleGlobalShortcuts(options: {\n char: string;\n key: { ctrl?: boolean };\n exit: () => void;\n state: ComposerState;\n}) {\n if (options.key.ctrl && options.char === \"c\") {\n options.exit();\n return true;\n }\n if (options.key.ctrl && (options.char === \"r\" || options.char === \"\\u0012\")) {\n applyHistoryMatch(options.state);\n return true;\n }\n return false;\n}\n\nfunction applyHistoryMatch(state: ComposerState) {\n const match = findReverseHistoryMatch(state.refs.history.current.entries(), state.input);\n if (!match) {\n state.setStatus(`No history match for \"${state.input}\"`);\n return;\n }\n state.setInput(match);\n state.setStatus(`History match: ${match}`);\n}\n\nexport function handleTypingKeys(\n options: ComposerKeyboardOptions & {\n char: string;\n key: { upArrow?: boolean; downArrow?: boolean; tab?: boolean };\n },\n) {\n if (options.key.upArrow) {\n options.state.setInput(options.state.refs.history.current.previous(options.state.input));\n return;\n }\n if (options.key.downArrow) {\n options.state.setInput(options.state.refs.history.current.next());\n return;\n }\n if (options.key.tab) completeTypingTab(options.state);\n}\n\nfunction completeTypingTab(state: ComposerState) {\n if (!state.inputSuggestions?.suggestions.length) return;\n const nextInput = applyInputSuggestion(state.input, state.inputSuggestions);\n state.setInput(nextInput);\n state.setStatus(`Completed ${state.inputSuggestions.suggestions[0]?.label ?? \"\"}`);\n}\n","import { useCallback } from \"react\";\nimport type { PromptSendResult } from \"./appTypes.ts\";\nimport type { ComposerState } from \"./useComposerState.ts\";\n\n/** Options for sending or queueing a prompt. */\nexport type SendPromptOptions = {\n /** Composer state container. */\n state: ComposerState;\n /** Remote send function. */\n sendMessage: (content: string) => Promise<void>;\n};\n\n/** Creates the enqueue-or-send prompt handler. */\nexport function useComposerSend(options: SendPromptOptions) {\n const { state, sendMessage } = options;\n return useCallback(\n async (prompt: string): Promise<PromptSendResult> => {\n if (state.refs.sendInProgress.current) return queuePrompt({ state, prompt });\n return flushPromptQueue({ state, prompt, sendMessage });\n },\n [sendMessage, state],\n );\n}\n\nasync function queuePrompt(input: {\n state: ComposerState;\n prompt: string;\n}): Promise<PromptSendResult> {\n const queue = input.state.refs.queuedPromptRef.current;\n queue.push(input.prompt);\n input.state.setQueuedPrompt(input.prompt);\n input.state.setStatus(\n queue.length === 1\n ? \"Queued prompt; it will send after the current response starts.\"\n : `Queued ${queue.length} prompts; they will send in order.`,\n );\n return \"queued\";\n}\n\nasync function flushPromptQueue(input: {\n state: ComposerState;\n prompt: string;\n sendMessage: (content: string) => Promise<void>;\n}): Promise<PromptSendResult> {\n input.state.refs.sendInProgress.current = true;\n try {\n await drainPromptQueue(input);\n input.state.setStatus(\"Ready\");\n return \"sent\";\n } finally {\n input.state.refs.sendInProgress.current = false;\n }\n}\n\nasync function drainPromptQueue(input: {\n state: ComposerState;\n prompt: string;\n sendMessage: (content: string) => Promise<void>;\n}) {\n const queue = input.state.refs.queuedPromptRef.current;\n let currentPrompt: string | null = input.prompt;\n while (currentPrompt) {\n input.state.setStatus(\"Sending...\");\n await input.sendMessage(currentPrompt);\n currentPrompt = queue.shift() ?? null;\n input.state.setQueuedPrompt(currentPrompt);\n }\n clearQueuedPrompt(input.state);\n}\n\nfunction clearQueuedPrompt(state: ComposerState) {\n state.refs.queuedPromptRef.current.length = 0;\n state.setQueuedPrompt(null);\n}\n","import { extractFileMentions } from \"@/features/store\";\nimport { type MutableRefObject, useMemo, useRef, useState } from \"react\";\nimport { getAllCommands, matchCommands } from \"../internal/cliRunner.ts\";\nimport type { InputMode } from \"./appTypes.ts\";\nimport { PromptHistory } from \"./composerHistory.ts\";\nimport type { InputSuggestionGroup } from \"./inputSuggestions.ts\";\n\n/** Mutable composer refs shared across keyboard and send handlers. */\nexport type ComposerRefs = {\n suppressNextSubmit: MutableRefObject<boolean>;\n lastEscapeAt: MutableRefObject<number>;\n stopShortcutRunning: MutableRefObject<boolean>;\n history: MutableRefObject<PromptHistory>;\n sendInProgress: MutableRefObject<boolean>;\n queuedPromptRef: MutableRefObject<string[]>;\n};\n\n/** Base composer state and derived lists. */\nexport type ComposerState = {\n input: string;\n setInput: (value: string) => void;\n status: string;\n setStatus: (value: string) => void;\n mode: InputMode;\n setMode: (value: InputMode) => void;\n selectedIdx: number;\n setSelectedIdx: (value: number | ((index: number) => number)) => void;\n inputSuggestions: InputSuggestionGroup | null;\n setInputSuggestions: (value: InputSuggestionGroup | null) => void;\n queuedPrompt: string | null;\n setQueuedPrompt: (value: string | null) => void;\n forceRender: (value: number | ((current: number) => number)) => void;\n refs: ComposerRefs;\n allCommands: ReturnType<typeof getAllCommands>;\n matches: ReturnType<typeof matchCommands>;\n fileMentions: string[];\n};\n\n/** Initializes composer state, refs, and derived command lists. */\nexport function useComposerState(): ComposerState {\n const ui = useComposerUiState();\n const refs = useComposerRefs();\n const derived = useComposerDerived(ui.input);\n return { ...ui, refs, ...derived };\n}\n\nfunction useComposerUiState() {\n const inputState = useComposerInputFields();\n const panelState = useComposerPanelFields();\n return { ...inputState, ...panelState };\n}\n\nfunction useComposerInputFields() {\n const [input, setInput] = useState(\"\");\n const [mode, setMode] = useState<InputMode>(\"typing\");\n const [selectedIdx, setSelectedIdx] = useState(0);\n return { input, setInput, mode, setMode, selectedIdx, setSelectedIdx };\n}\n\nfunction useComposerPanelFields() {\n const [status, setStatus] = useState(\"Ready\");\n const [inputSuggestions, setInputSuggestions] = useState<InputSuggestionGroup | null>(null);\n const [queuedPrompt, setQueuedPrompt] = useState<string | null>(null);\n const [, forceRender] = useState(0);\n return {\n status,\n setStatus,\n inputSuggestions,\n setInputSuggestions,\n queuedPrompt,\n setQueuedPrompt,\n forceRender,\n };\n}\n\nfunction useComposerDerived(input: string) {\n const allCommands = useMemo(() => getAllCommands(), []);\n const matches = useMemo(() => matchCommandInput({ input, allCommands }), [allCommands, input]);\n const fileMentions = useMemo(() => extractFileMentions(input), [input]);\n return { allCommands, matches, fileMentions };\n}\n\nfunction useComposerRefs(): ComposerRefs {\n return {\n suppressNextSubmit: useRef(false),\n lastEscapeAt: useRef(0),\n stopShortcutRunning: useRef(false),\n history: useRef(new PromptHistory()),\n sendInProgress: useRef(false),\n queuedPromptRef: useRef<string[]>([]),\n };\n}\n\nfunction matchCommandInput(options: {\n input: string;\n allCommands: ReturnType<typeof getAllCommands>;\n}) {\n if (!options.input.startsWith(\"/\")) return [];\n const partial = options.input.slice(1).split(\" \")[0];\n if (!partial) return options.allCommands;\n return matchCommands(partial);\n}\n","import { useEffect } from \"react\";\nimport { ESCAPE_CONTROL } from \"./composerConstants.ts\";\n\n/** Options for stdin escape forwarding. */\nexport type ComposerStdinEscapeOptions = {\n /** Escape press handler. */\n handleEscapePress: (now?: number) => void;\n};\n\n/** Forwards raw stdin escape bytes to the composer escape handler. */\nexport function useComposerStdinEscape(options: ComposerStdinEscapeOptions) {\n useEffect(() => {\n const handleStdinData = (chunk: Buffer | string) => {\n forwardEscapePresses({\n text: chunk.toString(),\n handleEscapePress: options.handleEscapePress,\n });\n };\n process.stdin.on(\"data\", handleStdinData);\n return () => {\n process.stdin.off(\"data\", handleStdinData);\n };\n }, [options.handleEscapePress]);\n}\n\nfunction forwardEscapePresses(input: { text: string; handleEscapePress: (now?: number) => void }) {\n const escapeCount = input.text.length - input.text.replaceAll(ESCAPE_CONTROL, \"\").length;\n if (escapeCount === 0) return;\n const now = Date.now();\n for (let index = 0; index < escapeCount; index += 1) {\n input.handleEscapePress(now + index);\n }\n}\n","import { useCallback } from \"react\";\nimport type { AppProps } from \"./appTypes.ts\";\nimport { isDoubleEscapePress } from \"./shortcuts.ts\";\nimport type { ComposerState } from \"./useComposerState.ts\";\n\n/** Options for stop and escape handling. */\nexport type ComposerStopOptions = {\n /** Composer state container. */\n state: ComposerState;\n /** App props containing the orchestrator. */\n props: AppProps;\n};\n\n/** Creates stop and escape handlers for the composer. */\nexport function useComposerStop(options: ComposerStopOptions) {\n const stopFromShortcut = useStopFromShortcut(options);\n const handleEscapePress = useHandleEscapePress({ ...options, stopFromShortcut });\n return { stopFromShortcut, handleEscapePress };\n}\n\nfunction useStopFromShortcut(options: ComposerStopOptions) {\n const { state, props } = options;\n return useCallback(() => {\n if (state.refs.stopShortcutRunning.current) return;\n runStopShortcut({ state, orchestrator: props.orchestrator });\n }, [props.orchestrator, state]);\n}\n\nfunction runStopShortcut(input: { state: ComposerState; orchestrator: AppProps[\"orchestrator\"] }) {\n input.state.refs.stopShortcutRunning.current = true;\n input.state.setStatus(\"Stopping ChatGPT...\");\n input.orchestrator\n .stopResponse()\n .then((stopped) => {\n input.state.setStatus(stopped ? \"Stopped active response.\" : \"No active response to stop.\");\n })\n .catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n input.state.setStatus(`Error: ${message}`);\n console.error(message);\n })\n .finally(() => {\n input.state.refs.stopShortcutRunning.current = false;\n input.state.forceRender((value) => value + 1);\n });\n}\n\nfunction useHandleEscapePress(options: ComposerStopOptions & { stopFromShortcut: () => void }) {\n const { state, stopFromShortcut } = options;\n return useCallback(\n (now = Date.now()) => {\n if (handleDoubleEscape({ state, stopFromShortcut, now })) return;\n if (state.mode === \"command-list\") {\n state.setMode(\"typing\");\n return;\n }\n state.setStatus(\"Press Esc again to stop ChatGPT\");\n },\n [state, stopFromShortcut],\n );\n}\n\nfunction handleDoubleEscape(input: {\n state: ComposerState;\n stopFromShortcut: () => void;\n now: number;\n}) {\n if (!isDoubleEscapePress(input.state.refs.lastEscapeAt.current, input.now)) {\n input.state.refs.lastEscapeAt.current = input.now;\n return false;\n }\n input.state.refs.lastEscapeAt.current = 0;\n input.state.setMode(\"typing\");\n input.stopFromShortcut();\n return true;\n}\n","export const DOUBLE_ESCAPE_WINDOW_MS = 800;\n\n/** Return true when a second Escape press lands inside the shortcut window. */\nexport function isDoubleEscapePress(previousPressAt: number, currentPressAt: number): boolean {\n return previousPressAt > 0 && currentPressAt - previousPressAt <= DOUBLE_ESCAPE_WINDOW_MS;\n}\n","import { useEffect } from \"react\";\nimport type { AppProps } from \"./appTypes.ts\";\nimport { loadInputSuggestions } from \"./inputSuggestions.ts\";\nimport type { ComposerState } from \"./useComposerState.ts\";\n\n/** Loads autocomplete suggestions whenever the composer input changes. */\nexport function useComposerSuggestions(state: ComposerState, props: AppProps) {\n useEffect(() => {\n let cancelled = false;\n loadInputSuggestions(state.input, {\n repoRoot: props.config.repoPath,\n commands: state.allCommands,\n })\n .then((suggestions) => {\n if (!cancelled) state.setInputSuggestions(suggestions);\n })\n .catch(() => {\n if (!cancelled) state.setInputSuggestions(null);\n });\n return () => {\n cancelled = true;\n };\n }, [props.config.repoPath, state.allCommands, state.input, state.setInputSuggestions]);\n}\n","import type { ComposerAssistPanelProps } from \"./ComposerAssistPanel.tsx\";\nimport type { ComposerInputBarProps } from \"./ComposerInputBar.tsx\";\nimport type { StatusBarProps } from \"./StatusBar.tsx\";\nimport { buildStatusBarProps } from \"./StatusBar.tsx\";\nimport type { AppProps } from \"./appTypes.ts\";\nimport { useComposerCommands } from \"./useComposerCommands.ts\";\nimport { useComposerInputHandlers } from \"./useComposerInput.ts\";\nimport { useComposerKeyboard, useComposerTabComplete } from \"./useComposerKeyboard.ts\";\nimport { useComposerSend } from \"./useComposerSend.ts\";\nimport { type ComposerState, useComposerState } from \"./useComposerState.ts\";\nimport { useComposerStdinEscape } from \"./useComposerStdin.ts\";\nimport { useComposerStop } from \"./useComposerStop.ts\";\nimport { useComposerSuggestions } from \"./useComposerSuggestions.ts\";\n\n/** View-model returned by the composer hook. */\nexport type ComposerView = {\n /** Status bar props. */\n statusBar: StatusBarProps;\n /** Input bar props. */\n inputBar: ComposerInputBarProps;\n /** Assist panel props. */\n assistPanel: ComposerAssistPanelProps;\n};\n\n/** Wires composer state, handlers, and keyboard shortcuts. */\nexport function useComposer(props: AppProps): ComposerView {\n const state = useComposerState();\n const handlers = useComposerHandlers({ state, props });\n return buildComposerView({ props, state, handlers });\n}\n\nfunction useComposerHandlers(input: { state: ComposerState; props: AppProps }) {\n useComposerSuggestions(input.state, input.props);\n const enqueueOrSendPrompt = useComposerSend({\n state: input.state,\n sendMessage: input.props.sendMessage,\n });\n useComposerStopEffects({ state: input.state, props: input.props });\n const runCommand = useComposerCommands({\n state: input.state,\n props: input.props,\n enqueueOrSendPrompt,\n });\n return useComposerInputLayer({ state: input.state, runCommand });\n}\n\nfunction useComposerStopEffects(options: { state: ComposerState; props: AppProps }) {\n const { handleEscapePress } = useComposerStop(options);\n useComposerStdinEscape({ handleEscapePress });\n}\n\nfunction useComposerInputLayer(options: {\n state: ComposerState;\n runCommand: (cmd: string) => Promise<void>;\n}) {\n const tabComplete = useComposerTabComplete(options.state);\n useComposerKeyboard({ state: options.state, runCommand: options.runCommand, tabComplete });\n return useComposerInputHandlers(options);\n}\n\nfunction buildComposerView(options: {\n props: AppProps;\n state: ComposerState;\n handlers: ReturnType<typeof useComposerInputHandlers>;\n}): ComposerView {\n const { props, state, handlers } = options;\n return {\n statusBar: buildStatusBarProps({ props, status: state.status, counter: props.counter }),\n inputBar: {\n input: state.input,\n onChange: handlers.handleInputChange,\n onSubmit: handlers.handleSubmit,\n },\n assistPanel: {\n mode: state.mode,\n inputSuggestions: state.inputSuggestions,\n matches: state.matches,\n selectedIdx: state.selectedIdx,\n fileMentions: state.fileMentions,\n queuedPrompt: state.queuedPrompt,\n },\n };\n}\n","import type { Command as CommanderCommand } from \"commander\";\n\n/** Merge parent-program and subcommand options (Commander hoists shared flags to the root). */\nexport function subcommandOpts<T extends object>(command: CommanderCommand): T {\n return { ...command.parent?.opts(), ...command.opts() } as T;\n}\n","import { DEFAULT_ASK_TIMEOUT_SECONDS } from \"@/config\";\nimport { DEFAULT_PROVIDER, PROVIDER_IDS } from \"@/features/providers\";\nimport type { Command } from \"commander\";\nimport type { ChatCmdOptions, ProjectCmdOptions, TaskCmdOptions } from \"./cliTypes.ts\";\nimport {\n CliRunner,\n runChatList,\n runChatMove,\n runDownload,\n runProjectCreate,\n runProjectList,\n runServe,\n runTaskCreate,\n runTaskList,\n} from \"./internal/cliRunner.ts\";\nimport { subcommandOpts } from \"./subcommandOpts.ts\";\n\n/** `--provider` help text, derived from the registry so it never goes stale. */\nconst PROVIDER_OPTION = `Browser provider: ${PROVIDER_IDS.join(\", \")} (default: ${DEFAULT_PROVIDER})`;\n\n/** Register all bridge CLI commands on a Commander program. */\nexport function registerCliCommands(program: Command, runner = new CliRunner()): void {\n program\n .name(\"bridge\")\n .description(\"Terminal CLI that bridges ChatGPT or Gemini with local tools via MCP\")\n .version(\"0.1.0\")\n .option(\"-r, --repo <path>\", \"Path to the target repository (default: cwd)\")\n .option(\"-p, --port <number>\", \"MCP server port (default: 8765)\")\n .option(\"--provider <name>\", PROVIDER_OPTION)\n .option(\"--no-browser\", \"Skip Chrome browser connection\")\n .action((...args: unknown[]) => handleDefaultAction(args, runner));\n registerHeadlessCommands(program, runner);\n registerWorkspaceCommands(program);\n}\n\n/** Register non-interactive headless subcommands. */\nfunction registerHeadlessCommands(program: Command, runner: CliRunner): void {\n program\n .command(\"ask <prompt...>\")\n .description(\"Send one prompt and print the reply (non-interactive)\")\n .option(\"-r, --repo <path>\", \"Target repository for MCP tools\")\n .option(\"-p, --port <number>\", \"MCP server port\")\n .option(\"--provider <names>\", `${PROVIDER_OPTION}; comma-separated for fan-out`)\n .option(\"--strict\", \"Fan-out: exit non-zero if any provider fails (default: only if all fail)\")\n .option(\"--json\", \"Emit a JSON object { sessionId, model, reply, contextTokens }\")\n .option(\n \"--tools\",\n \"Start the tunnel + connector so ChatGPT can call local tools (ChatGPT only)\",\n )\n .option(\"--fresh\", \"Start a new conversation before asking\")\n .option(\"--conversation <idOrUrl>\", \"Open a ChatGPT conversation by id or URL before asking\")\n .option(\"--model <name>\", \"Switch model before asking\")\n .option(\n \"--timeout <seconds>\",\n `Max seconds to wait for the reply (default ${DEFAULT_ASK_TIMEOUT_SECONDS})`,\n )\n .option(\"--attach <path...>\", \"Attach repo-relative image file(s) before asking\")\n .option(\n \"--images <count>\",\n \"Wait for ChatGPT to finish generating this many images before returning\",\n )\n .action((...args: unknown[]) => handleAskAction(args, runner));\n program\n .command(\"download\")\n .description(\"Download a conversation's attachments/images (non-interactive, ChatGPT only)\")\n .option(\"-r, --repo <path>\", \"Target repository\")\n .option(\"-p, --port <number>\", \"MCP server port\")\n .option(\"--provider <name>\", PROVIDER_OPTION)\n .option(\"--conversation <id>\", \"Conversation id (default: current page)\")\n .option(\"--out <dir>\", \"Output directory (default: ./downloads/<id>)\")\n .option(\"--id <attachmentId...>\", \"Specific attachment id(s); omit to download all\")\n .option(\"--scan\", \"Rescan conversation attachments into manifest without downloading\")\n .option(\"--json\", \"Emit a JSON array of results\")\n .action((...args: unknown[]) => handleDownloadAction(args));\n program\n .command(\"sessions\")\n .description(\"List stored bridge sessions as JSON\")\n .action(() => runner.runSessions());\n program\n .command(\"login\")\n .description(\"Open the bridge Chrome profile to sign in once\")\n .option(\"-r, --repo <path>\", \"Target repository for the bridge Chrome profile\")\n .option(\"--provider <name>\", PROVIDER_OPTION)\n .action((...args: unknown[]) => handleLoginAction(args, runner));\n program\n .command(\"stop\")\n .description(\"Close the warm bridge browser\")\n .action(() => runner.runStop());\n program\n .command(\"serve\")\n .description(\"Serve the outbound MCP `ask` tool over stdio so other agents can drive web chats\")\n .option(\"-r, --repo <path>\", \"Target repository for the bridge Chrome profile\")\n .option(\n \"--timeout <seconds>\",\n \"Default per-provider reply timeout when an `ask` caller omits one\",\n )\n .action((...args: unknown[]) => handleServeAction(args));\n}\n\n/** Attach the shared repo/port/provider/json flags to a workspace leaf command. */\nfunction withWorkspaceFlags(command: Command): Command {\n return command\n .option(\"-r, --repo <path>\", \"Target repository for the bridge Chrome profile\")\n .option(\"-p, --port <number>\", \"MCP server port\")\n .option(\"--provider <name>\", PROVIDER_OPTION)\n .option(\"--json\", \"Emit JSON instead of human-readable lines\");\n}\n\n/** Register `project`, `chat`, and `task` workspace subcommands (ChatGPT only). */\nfunction registerWorkspaceCommands(program: Command): void {\n const project = program.command(\"project\").description(\"Manage ChatGPT Projects (ChatGPT only)\");\n withWorkspaceFlags(project.command(\"list\"))\n .description(\"List ChatGPT Projects\")\n .action((...args: unknown[]) => handleWorkspace<ProjectCmdOptions>(args, runProjectList));\n withWorkspaceFlags(project.command(\"create <name...>\"))\n .description(\"Create a ChatGPT Project\")\n .option(\"--instructions <text>\", \"Optional project instructions\")\n .action((...args: unknown[]) => handleWorkspaceArg<ProjectCmdOptions>(args, runProjectCreate));\n\n const chat = program\n .command(\"chat\")\n .description(\"List or organize ChatGPT conversations (ChatGPT only)\");\n withWorkspaceFlags(chat.command(\"list\"))\n .description(\"List sidebar (project-less) conversations\")\n .option(\"--orphans\", \"List only loose, project-less conversations\")\n .action((...args: unknown[]) => handleWorkspace<ChatCmdOptions>(args, runChatList));\n withWorkspaceFlags(chat.command(\"move <idOrTitle...>\"))\n .description(\"Move a conversation into a Project\")\n .option(\"--project <name>\", \"Destination project name\")\n .action((...args: unknown[]) => handleWorkspaceArg<ChatCmdOptions>(args, runChatMove));\n\n const task = program.command(\"task\").description(\"List or schedule ChatGPT Tasks (ChatGPT only)\");\n withWorkspaceFlags(task.command(\"list\"))\n .description(\"List ChatGPT Scheduled tasks\")\n .action((...args: unknown[]) => handleWorkspace<TaskCmdOptions>(args, runTaskList));\n withWorkspaceFlags(task.command(\"create <prompt...>\"))\n .description(\"Schedule a task via natural language\")\n .option(\"--every <spec>\", \"Recurring cadence (e.g. day, or weekday at 9am)\")\n .option(\"--at <spec>\", \"One-off run time (e.g. tomorrow at 9am)\")\n .action((...args: unknown[]) => handleWorkspaceArg<TaskCmdOptions>(args, runTaskCreate));\n}\n\n/** Run a no-positional workspace verb from Commander action arguments. */\nfunction handleWorkspace<T extends object>(\n args: unknown[],\n run: (options: T) => Promise<void>,\n): void {\n const command = args.at(-1) as Command;\n void run(command.optsWithGlobals() as T);\n}\n\n/** Run a variadic-positional workspace verb (name/title/prompt) from Commander action arguments. */\nfunction handleWorkspaceArg<T extends object>(\n args: unknown[],\n run: (value: string, options: T) => Promise<void>,\n): void {\n const command = args.at(-1) as Command;\n const parts = (args[0] ?? []) as string[];\n void run(parts.join(\" \"), command.optsWithGlobals() as T);\n}\n\n/** Run default `bridge` TUI from Commander action arguments. */\nfunction handleDefaultAction(args: unknown[], runner: CliRunner): void {\n const command = args.at(-1) as Command;\n void runner.runDefault(command.opts());\n}\n\n/**\n * Run `bridge ask` from Commander action arguments.\n *\n * For a variadic `<prompt...>`, Commander calls the action with\n * `(promptParts, options, command)` — the prompt words are the first argument,\n * not every argument before the command. Joining `args.slice(0, -1)` instead\n * swept the options object into the prompt, appending a literal `[object\n * Object]` to whatever the user asked.\n */\nfunction handleAskAction(args: unknown[], runner: CliRunner): void {\n const command = args.at(-1) as Command;\n const promptParts = (args[0] ?? []) as string[];\n void runner.runAsk(promptParts.join(\" \"), subcommandOpts(command));\n}\n\n/** Run `bridge download` from Commander action arguments. */\nfunction handleDownloadAction(args: unknown[]): void {\n const command = args.at(-1) as Command;\n void runDownload(subcommandOpts(command));\n}\n\n/** Run `bridge serve` from Commander action arguments (blocks until the client disconnects). */\nfunction handleServeAction(args: unknown[]): Promise<void> {\n const command = args.at(-1) as Command;\n return runServe(subcommandOpts(command));\n}\n\n/** Run `bridge login` from Commander action arguments. */\nfunction handleLoginAction(args: unknown[], runner: CliRunner): void {\n const command = args.at(-1) as Command;\n void runner.runLogin(subcommandOpts(command));\n}\n","/**\n * Effect Schema definitions for the terminal feature.\n *\n * These schemas provide runtime validation and type derivation for the CLI\n * option interfaces consumed by Commander commands and the headless runners.\n * The existing implementations (`cliRunner.ts`, `registerCli.ts`) remain\n * unchanged — these schemas are additive and exported through the door.\n *\n * @module\n */\nimport { Schema } from \"effect\";\n\n// ---------------------------------------------------------------------------\n// CommonCliOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the common CLI flags shared by interactive and headless commands.\n */\nexport const CommonCliOptionsSchema = Schema.Struct({\n repo: Schema.optional(Schema.String).annotations({\n description: \"Target repository path.\",\n }),\n port: Schema.optional(Schema.String).annotations({\n description: \"MCP listen port.\",\n }),\n provider: Schema.optional(Schema.String).annotations({\n description: \"Browser provider id.\",\n }),\n});\n\n/**\n * CommonCliOptions type derived from the schema.\n */\nexport type CommonCliOptionsFromSchema = Schema.Schema.Type<typeof CommonCliOptionsSchema>;\n\n// ---------------------------------------------------------------------------\n// AskOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the non-interactive `bridge ask` command options.\n */\nexport const AskOptionsSchema = Schema.Struct({\n repo: Schema.optional(Schema.String).annotations({\n description: \"Target repository path.\",\n }),\n port: Schema.optional(Schema.String).annotations({\n description: \"MCP listen port.\",\n }),\n provider: Schema.optional(Schema.String).annotations({\n description: \"Browser provider id.\",\n }),\n fresh: Schema.optional(Schema.Boolean).annotations({\n description: \"Start a fresh conversation before sending.\",\n }),\n model: Schema.optional(Schema.String).annotations({\n description: 'Switch model before sending (e.g. \"GPT-4o\" or \"Gemini Flash\").',\n }),\n tools: Schema.optional(Schema.Boolean).annotations({\n description: \"Bring up the tunnel + connector so ChatGPT can call local MCP tools.\",\n }),\n json: Schema.optional(Schema.Boolean).annotations({\n description: \"Emit a JSON object instead of plain reply text.\",\n }),\n timeout: Schema.optional(Schema.String).annotations({\n description: \"Max seconds to wait for the reply.\",\n }),\n conversation: Schema.optional(Schema.String).annotations({\n description: \"Conversation id or full ChatGPT URL to open before asking (omit with --fresh).\",\n }),\n attach: Schema.optional(Schema.Array(Schema.String)).annotations({\n description: \"Repo-relative image paths to attach in ChatGPT before sending the prompt.\",\n }),\n images: Schema.optional(Schema.String).annotations({\n description: \"Number of images to wait for when the prompt asks ChatGPT to generate images.\",\n }),\n strict: Schema.optional(Schema.Boolean).annotations({\n description:\n \"With a multi-provider fan-out, exit non-zero if any provider fails (default: only if all fail).\",\n }),\n});\n\n/**\n * AskOptions type derived from the schema.\n */\nexport type AskOptionsFromSchema = Schema.Schema.Type<typeof AskOptionsSchema>;\n\n// ---------------------------------------------------------------------------\n// ServeOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the `bridge serve` outbound MCP gateway command options.\n */\nexport const ServeOptionsSchema = Schema.Struct({\n repo: Schema.optional(Schema.String).annotations({\n description: \"Target repository path.\",\n }),\n port: Schema.optional(Schema.String).annotations({\n description: \"MCP listen port.\",\n }),\n provider: Schema.optional(Schema.String).annotations({\n description: \"Browser provider id.\",\n }),\n timeout: Schema.optional(Schema.String).annotations({\n description: \"Default per-provider reply timeout in seconds when a caller omits it.\",\n }),\n});\n\n/**\n * ServeOptions type derived from the schema.\n */\nexport type ServeOptionsFromSchema = Schema.Schema.Type<typeof ServeOptionsSchema>;\n\n// ---------------------------------------------------------------------------\n// DownloadCmdOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the non-interactive `bridge download` command options.\n */\nexport const DownloadCmdOptionsSchema = Schema.Struct({\n repo: Schema.optional(Schema.String).annotations({\n description: \"Target repository path.\",\n }),\n port: Schema.optional(Schema.String).annotations({\n description: \"MCP listen port.\",\n }),\n provider: Schema.optional(Schema.String).annotations({\n description: \"Browser provider id.\",\n }),\n conversation: Schema.optional(Schema.String).annotations({\n description: \"Conversation id to read from; defaults to the current page's `/c/<id>`.\",\n }),\n out: Schema.optional(Schema.String).annotations({\n description: \"Output directory; defaults to `./downloads/<conversationId>` when omitted.\",\n }),\n id: Schema.optional(Schema.Array(Schema.String)).annotations({\n description: \"Specific attachment id(s); omit to download every attachment.\",\n }),\n scan: Schema.optional(Schema.Boolean).annotations({\n description: \"Rescan conversation attachments into manifest without downloading files.\",\n }),\n json: Schema.optional(Schema.Boolean).annotations({\n description: \"Emit a JSON array of results instead of plain lines.\",\n }),\n});\n\n/**\n * DownloadCmdOptions type derived from the schema.\n */\nexport type DownloadCmdOptionsFromSchema = Schema.Schema.Type<typeof DownloadCmdOptionsSchema>;\n\n// ---------------------------------------------------------------------------\n// LoginOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for the non-interactive `bridge login` command options.\n */\nexport const LoginOptionsSchema = Schema.Struct({\n repo: Schema.optional(Schema.String).annotations({\n description: \"Target repository path.\",\n }),\n provider: Schema.optional(Schema.String).annotations({\n description: \"Browser provider id to sign into.\",\n }),\n});\n\n/**\n * LoginOptions type derived from the schema.\n */\nexport type LoginOptionsFromSchema = Schema.Schema.Type<typeof LoginOptionsSchema>;\n\n// ---------------------------------------------------------------------------\n// ProjectCmdOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for `bridge project` subcommand options (ChatGPT Projects).\n */\nexport const ProjectCmdOptionsSchema = Schema.Struct({\n repo: Schema.optional(Schema.String).annotations({\n description: \"Target repository path.\",\n }),\n port: Schema.optional(Schema.String).annotations({\n description: \"MCP listen port.\",\n }),\n provider: Schema.optional(Schema.String).annotations({\n description: \"Browser provider id.\",\n }),\n json: Schema.optional(Schema.Boolean).annotations({\n description: \"Emit JSON instead of human-readable lines.\",\n }),\n instructions: Schema.optional(Schema.String).annotations({\n description: \"Optional project instructions applied on create.\",\n }),\n});\n\n/**\n * ProjectCmdOptions type derived from the schema.\n */\nexport type ProjectCmdOptionsFromSchema = Schema.Schema.Type<typeof ProjectCmdOptionsSchema>;\n\n// ---------------------------------------------------------------------------\n// ChatCmdOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for `bridge chat` subcommand options (list / move conversations).\n */\nexport const ChatCmdOptionsSchema = Schema.Struct({\n repo: Schema.optional(Schema.String).annotations({\n description: \"Target repository path.\",\n }),\n port: Schema.optional(Schema.String).annotations({\n description: \"MCP listen port.\",\n }),\n provider: Schema.optional(Schema.String).annotations({\n description: \"Browser provider id.\",\n }),\n json: Schema.optional(Schema.Boolean).annotations({\n description: \"Emit JSON instead of human-readable lines.\",\n }),\n orphans: Schema.optional(Schema.Boolean).annotations({\n description: \"List only loose, project-less conversations (the sidebar Recents).\",\n }),\n project: Schema.optional(Schema.String).annotations({\n description: \"Destination project name for `chat move`.\",\n }),\n});\n\n/**\n * ChatCmdOptions type derived from the schema.\n */\nexport type ChatCmdOptionsFromSchema = Schema.Schema.Type<typeof ChatCmdOptionsSchema>;\n\n// ---------------------------------------------------------------------------\n// TaskCmdOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for `bridge task` subcommand options (ChatGPT Scheduled tasks).\n */\nexport const TaskCmdOptionsSchema = Schema.Struct({\n repo: Schema.optional(Schema.String).annotations({\n description: \"Target repository path.\",\n }),\n port: Schema.optional(Schema.String).annotations({\n description: \"MCP listen port.\",\n }),\n provider: Schema.optional(Schema.String).annotations({\n description: \"Browser provider id.\",\n }),\n json: Schema.optional(Schema.Boolean).annotations({\n description: \"Emit JSON instead of human-readable lines.\",\n }),\n every: Schema.optional(Schema.String).annotations({\n description: 'Recurring cadence phrase, e.g. \"day\" or \"weekday at 9am\".',\n }),\n at: Schema.optional(Schema.String).annotations({\n description: 'One-off run time phrase, e.g. \"tomorrow at 9am\".',\n }),\n});\n\n/**\n * TaskCmdOptions type derived from the schema.\n */\nexport type TaskCmdOptionsFromSchema = Schema.Schema.Type<typeof TaskCmdOptionsSchema>;\n\n// ---------------------------------------------------------------------------\n// DownloadResult\n// ---------------------------------------------------------------------------\n\n/**\n * Schema for a single attachment download outcome, success or failure.\n */\nexport const DownloadResultSchema = Schema.Struct({\n id: Schema.optional(Schema.String).annotations({\n description: \"Attachment identifier.\",\n }),\n path: Schema.String.annotations({\n description: \"Local file path where the download was saved.\",\n }),\n bytes: Schema.Number.annotations({\n description: \"Size in bytes of the downloaded file.\",\n }),\n error: Schema.optional(Schema.String).annotations({\n description: \"Error message if the download failed.\",\n }),\n});\n\n/**\n * DownloadResult type derived from the schema.\n */\nexport type DownloadResultFromSchema = Schema.Schema.Type<typeof DownloadResultSchema>;\n"],"mappings":"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","names":["Effect","execFile","mkdir","writeFile","basename","dirname","extname","isAbsolute","join","relative","resolve","attachmentId","basename","path","spawn","join","resolve","randomUUID","mkdir","readFile","readdir","stat","writeFile","homedir","join","resolve","isNodeError","readFile","stat","resolve","readFile","path","commands","readFile","isNodeError","isRecord","Schema","path","resolve","readFile","stat","isRecord","Schema","join","mkdir","writeFile","homedir","randomUUID","isRecord","path","readFile","readdir","detail","resolve","stat","Schema","DEFAULT_CONNECTOR_NAME","normalizeDisplayText","captureLastResponse","SELECTORS","countAssistantResponses","captureAllMessages","rewindLastUserPrompt","stopGenerating","attachFilesToPrompt","isLikelyModelLabel","readModelFromTrigger","firstVisible","detectCurrentModel","listAvailableModels","selectModel","isGuestSession","assertSignedIn","readSidebarConversations","navigateToConversation","newConversation","injectPrompt","composerClears","readComposerText","remainingTimeout","isTransientAssistantText","waitForResponseAfterBaseline","SETTLE_QUIET_MS","isTurnSettled","waitForResponse","waitForLastAssistantTextStable","resolve","join","spawn","Schema","McpProtocolServer","z","resolve","Schema","execFile","spawn","Data","spawn","resolve","spawn","spawnCloudflared","attachTunnelOutput","attachTunnelLifecycle","waitForTunnelUrl","resolve","mkdir","readFile","writeFile","dirname","readFile","path","mkdir","dirname","writeFile","mapCapturedMessages","resolve","execFile","sessionStore","resolve","Schema","Schema","Box","Box","Text","jsx","jsxs","Box","Text","Box","Text","jsx","jsxs","Box","Text","jsx","jsxs","Box","Text","Box","Text","jsx","jsxs","jsxs","Box","jsx","Text","useCallback","useCallback","useCallback","sep","readdir","readdir","path","readdir","sep","path","IGNORED_COMPLETION_ENTRIES","sep","readdir","useCallback","useCallback","useMemo","useMemo","useCallback","useCallback","useEffect","useEffect","jsx","jsxs","Box","mcpConnectorUrl","splitArgs","DOWNLOADER_MODULE","conversationIdFromPage","isRecord","loadDownloader","normalizeDownloadResult","normalizeDownloadAll","isAbsolute","relative","resolve","path","extname","basename","execFile","join","mkdir","chromium","dirname","writeFile","checkpointId","openConnectorSetup","execFile","assertSignedIn","resolve","conversationIdFromPage","program","program","Schema","Effect"]}