/** * Type definitions and interfaces for CLI tools */ import type { AgentModeSpec, CaptureSpec, ComposerSpec, GracefulExitSpec, NavigationKeySpec, ToolLivenessSpec } from '../../types/cli-tool-contracts'; /** * CLI Tool IDs constant array * T2.1: Single source of truth for CLI tool IDs * CLIToolType is derived from this constant (DRY principle) */ export declare const CLI_TOOL_IDS: readonly ["claude", "codex", "gemini", "vibe-local", "opencode", "copilot", "antigravity", "command-code"]; /** * CLIツールタイプ * Derived from CLI_TOOL_IDS for type safety and sync */ export type CLIToolType = typeof CLI_TOOL_IDS[number]; /** * Whether a CLI tool renders in the terminal's alternate screen, making the * captured line count useless as a "how far have I read" cursor (Issue #1268). * * @param cliToolId - CLI tool identifier * @returns True when line counts must not be used for deduplication */ export declare function usesAlternateScreen(cliToolId: CLIToolType): boolean; /** * Whether a stored `last_captured_line` still indexes into THIS capture, i.e. * whether it may be used as a "how far have I read" cursor (Issue #1910). * * Two independent things pin a captured line count so it stops growing with the * transcript, and a caller that slices at the stored cursor has to survive both: * * - **the tool renders in the alternate screen** ({@link usesAlternateScreen}): * tmux keeps no scrollback, every capture returns exactly `pane_height` rows, * and the count is pinned there from the very first frame (Issue #1268); * - **the capture window saturated** (`isCaptureWindowSaturated` in * `lib/tmux/tmux-capture-cache.ts`): the pane outgrew the sliding window the * capture is taken through, so the count is pinned at the window size and the * window merely slides (Issue #1670). * * Either one makes a previously stored index denote a different line — or no * line at all — so `lines.slice(cursor)` silently yields nothing. That is * Issue #1910: `commandmate capture ` printed a single empty byte for every * alternate-screen session that had taken one turn, because the poller had * stored the pane height (1000 on copilot / claude, 200 on opencode) and the * next frame is exactly that many rows. * * A caller that reads `false` must fall back to the WHOLE capture: repeating * rows the reader has already seen is harmless, dropping new output is not. * * The two conditions are stated together here rather than at each call site * because they are one rule — "is the count a cursor?" — reached from two * sides, and #1670 fixed only the second one in * `src/lib/session/current-output-builder.ts` while `src/lib/polling/ * response-checker.ts` (which spells the same expression inline as * `lineCountIsCursor`) already had both. Folding that second copy in here is * left to the next change that touches the poller. * * @param cliToolId - CLI tool the capture came from * @param captureWindowSaturated - Whether this capture came back clipped by the window * @returns True when the stored line count is still a usable cursor */ export declare function capturedLineCountIsCursor(cliToolId: CLIToolType, captureWindowSaturated: boolean): boolean; /** * Maximum number of agent instances allowed per worktree (Issue #868). * Caps how many concurrent sessions — including multiple instances of the same * CLI tool — a single worktree may hold. */ export declare const MAX_AGENT_INSTANCES = 10; /** * Maximum length for an agent instance alias (display name). */ export declare const MAX_AGENT_ALIAS_LENGTH = 50; /** * Valid instance ID character pattern (Issue #868). * Mirrors SESSION_NAME_PATTERN constraints so instance IDs can be embedded in * tmux session names without triggering command-injection defenses. * Length is bounded to keep generated session names well under tmux limits. */ export declare const INSTANCE_ID_PATTERN: RegExp; /** Maximum length for an instance ID. */ export declare const MAX_INSTANCE_ID_LENGTH = 64; /** * Agent instance definition (Issue #868). * * Replaces the implicit `(worktreeId, cliToolId)` identity with an explicit, * stable `(worktreeId, instanceId)` identity that supports multiple instances * of the same CLI tool within one worktree. * * The PRIMARY instance of a CLI tool has `id === cliTool`, which keeps existing * session names, poller keys, and DB rows byte-for-byte identical (backward * compatibility / migration anchor). */ export interface AgentInstance { /** Stable instance identifier. Primary instance: `id === cliTool`. */ id: string; /** CLI tool backing this instance. */ cliTool: CLIToolType; /** Human-readable display name (defaults to the CLI tool's display name). */ alias: string; /** Sort order within the worktree (0-based). */ order: number; } /** * Validate an instance ID string (Issue #868). * @param id - Candidate instance ID * @returns True if the ID is a safe, bounded identifier */ export declare function isValidInstanceId(id: string): id is string; /** * Get the primary instance ID for a CLI tool (Issue #868). * The primary instance is identified by `instanceId === cliTool`, which is the * backward-compatibility anchor: session names / poller keys / DB rows are * unchanged for the primary instance. * * @param cliTool - CLI tool type * @returns The primary instance ID (equal to the cliTool id) */ export declare function getPrimaryInstanceId(cliTool: CLIToolType): string; /** * Determine whether an instance ID refers to the primary instance of a CLI tool. * * @param instanceId - Instance ID (may be undefined → treated as primary) * @param cliTool - CLI tool type * @returns True when the instance is the primary instance */ export declare function isPrimaryInstance(instanceId: string | undefined, cliTool: CLIToolType): boolean; /** * Build a non-primary instance ID from a suffix (Issue #868). * Format: `{cliTool}-{suffix}` (e.g. `claude-2`). Keeps the CLI tool encoded in * the ID so the backing tool can be recovered without a DB lookup. * * @param cliTool - CLI tool type * @param suffix - Distinguishing suffix (alphanumeric/underscore/hyphen) * @returns Composite instance ID */ export declare function buildInstanceId(cliTool: CLIToolType, suffix: string): string; /** * Derive the tmux session-name suffix for a (non-primary) instance (Issue #868). * Strips a leading `{cliTool}-` prefix so `claude-2` yields `2`, avoiding a * redundant `mcbd-claude-{wt}-claude-2` session name. Falls back to the raw ID. * * @param instanceId - Instance ID * @param cliTool - CLI tool type * @returns Session-name-safe suffix */ export declare function deriveSessionSuffix(instanceId: string, cliTool: CLIToolType): string; /** * SWE CLIツールの共通インターフェース */ export interface ICLITool { /** CLIツールの識別子 (claude, codex, gemini, vibe-local, opencode) */ readonly id: CLIToolType; /** CLIツールの表示名 */ readonly name: string; /** CLIツールのコマンド名 */ readonly command: string; /** * CLIツールがインストールされているか確認 * @returns インストールされている場合true */ isInstalled(): Promise; /** * セッションが実行中かチェック * @param worktreeId - Worktree ID * @param instanceId - Agent instance ID (Issue #868). Defaults to the primary instance. * @returns 実行中の場合true */ isRunning(worktreeId: string, instanceId?: string): Promise; /** * 新しいセッションを開始 * @param worktreeId - Worktree ID * @param worktreePath - Worktreeのパス * @param instanceId - Agent instance ID (Issue #868). Defaults to the primary instance. */ startSession(worktreeId: string, worktreePath: string, instanceId?: string): Promise; /** * メッセージを送信 * @param worktreeId - Worktree ID * @param message - 送信するメッセージ * @param instanceId - Agent instance ID (Issue #868). Defaults to the primary instance. */ sendMessage(worktreeId: string, message: string, instanceId?: string): Promise; /** * セッションを終了 * @param worktreeId - Worktree ID * @param instanceId - Agent instance ID (Issue #868). Defaults to the primary instance. */ killSession(worktreeId: string, instanceId?: string): Promise; /** * セッション名を取得 * @param worktreeId - Worktree ID * @param instanceId - Agent instance ID (Issue #868). Defaults to the primary instance. * @returns セッション名 */ getSessionName(worktreeId: string, instanceId?: string): string; /** * 処理を中断(Escapeキー送信) * @param worktreeId - Worktree ID * @param instanceId - Agent instance ID (Issue #868). Defaults to the primary instance. */ interrupt(worktreeId: string, instanceId?: string): Promise; /** * Describe this tool's input box (Issue #1933, §6.3). * * How the composer is recognised on a captured frame, how many rows a submit * read-back must ask for, whether it may be emptied before typing, and how * many Enter presses submit. `sendMessageWithSubmitVerification` takes the * result, which is what keeps the four facts in one declaration per tool * instead of in four tables keyed on {@link CLIToolType}. */ describeComposer(): ComposerSpec; /** * Describe how this tool is asked to quit (Issue #1933, §13.2). * * The keystrokes, the shutdown window they need, and whether the tool owns a * loopback server whose port must be confirmed dead before it is reused. */ gracefulExitSequence(): GracefulExitSpec; /** * Describe what a status capture of this tool must ask tmux for * (Issue #1933, §10.12). */ captureSpec(): CaptureSpec; /** * Describe how this tool's pane is read for "did the TOOL exit?" * (Issue #2070). * * A tmux session outlives the process it was created for whenever the agent * quits, updates itself or crashes, and `has-session` cannot tell the * difference. Until this Issue only claude could — through one * `cliToolId === 'claude'` branch in `worktree-status-helper` — so a codex * session that had fallen back to the shell kept a green dot and failed every * subsequent `send` in `waitForPrompt`. * * See {@link ToolLivenessSpec} for the rule the declaration fills in. */ livenessSpec(): ToolLivenessSpec; /** * Declare the keys this tool's terminal UI may send (Issue #2046). * * `POST /api/worktrees/[id]/special-keys` validates against the answer for * the tool it was given, instead of against one global list shared by every * tool. See {@link NavigationKeySpec} for why a shared list stopped working * once opencode's `ctrl+x`-leader chords arrived, and for the #2032 invariant * every declaration has to keep. */ navigationKeys(): NavigationKeySpec; /** * Declare how this tool cycles its permission mode, or `null` (Issue #2592). * * Six of the eight supported CLIs put a permission / approval mode on * `shift+tab`, and until this Issue CommandMate had no way to send it from a * surface: the terminal is read-only, so the only workaround was * `commandmate attach` on the same machine. The SEND half was already there — * `BTab` has been in every tool's {@link navigationKeys} since #473 and in the * tmux allow-list since #2032 — what was missing was a declaration saying what * the key MEANS for this tool and how the resulting mode is read back. * * Both halves are in one declaration because neither is useful alone: a button * with no read-back is a blind press (four of the five declaring tools draw * nothing in their base mode), and a read-back with no button is a label for a * thing the operator still cannot change. * * See {@link AgentModeSpec} for the measurement table, and for why opencode * (whose `BTab` switches agents, not modes), vibe-local (no binding) and * gemini (binding documented, footer never measured) declare nothing. */ agentModeSpec(): AgentModeSpec | null; } /** * CLI tool display names for UI rendering * Issue #368: Centralized display name mapping * * Usage: UI display (tab headers, message lists, settings). * For internal logs/debug, use tool.name (BaseCLITool.name) instead. */ export declare const CLI_TOOL_DISPLAY_NAMES: Record; /** * Check if a string is a valid CLIToolType * Issue #368: Type guard for safe casting of untrusted CLI tool ID strings * * @param value - String to check * @returns True if value is a valid CLIToolType */ export declare function isCliToolType(value: string): value is CLIToolType; /** * Get the display name for a CLI tool ID * Issue #368: Centralized display name function for DRY compliance * * @param id - CLI tool type identifier * @returns Human-readable display name */ export declare function getCliToolDisplayName(id: CLIToolType): string; /** * Get the display name for a CLI tool ID string, with fallback for unknown IDs * Issue #368: Safe wrapper for UI components receiving untyped cliToolId strings * * Unlike getCliToolDisplayName(), this accepts optional/untyped strings and * returns a fallback value ('Assistant') for null, undefined, or unknown IDs. * * @param cliToolId - Optional CLI tool ID string (may be untyped) * @param fallback - Fallback display name for missing/unknown IDs (default: 'Assistant') * @returns Human-readable display name or fallback */ export declare function getCliToolDisplayNameSafe(cliToolId?: string, fallback?: string): string; /** * Resolve a human-readable label for an agent instance (Issue #869). * * Alias-first: returns the instance alias when it is a non-empty string, * otherwise falls back to the backing CLI tool's display name. Use this for all * UI surfaces (header badge, terminal tabs, split selector) so additional * instances of the same tool remain distinguishable. * * @param instance - Agent instance (or a minimal `{ cliTool, alias }` shape) * @returns Non-empty display label */ export declare function getInstanceLabel(instance: { cliTool: CLIToolType; alias?: string; }): string; /** * Resolve the alias-aware display label for the *active* agent instance within * a roster (Issue #956). * * Finds the instance whose id matches `activeInstanceId` and returns its label * via {@link getInstanceLabel} (alias-first). When no instance matches — e.g. a * stale `activeInstanceId` or an empty roster — falls back to the bare CLI tool * display name so callers still render something sensible. * * Used by the kill-session confirmation dialog so it shows the user-defined * alias (e.g. "レビュー担当") instead of the raw CLI tool name (e.g. "Claude"). * * @param instances - Agent instance roster * @param activeInstanceId - Id of the currently active instance * @param fallbackCliTool - CLI tool used when no instance matches * @returns Non-empty display label */ export declare function getActiveInstanceLabel(instances: ReadonlyArray<{ id: string; cliTool: CLIToolType; alias?: string; }>, activeInstanceId: string, fallbackCliTool: CLIToolType): string; /** * Build the default set of agent instances from a worktree's selectedAgents * (Issue #868 migration / fallback). * * Each selected tool becomes its own PRIMARY instance (`id === cliTool`), so a * worktree with no explicit instance configuration behaves exactly as before. * * @param selectedAgents - Ordered list of selected CLI tools * @returns One primary AgentInstance per selected tool, preserving order */ export declare function agentInstancesFromSelectedAgents(selectedAgents: CLIToolType[]): AgentInstance[]; /** * Minimum context window size for vibe-local. * [S1-007] Lower bound rationale: Ollama's actual minimum context window is * typically 2048+, but 128 is set as a permissive lower bound to accommodate * custom models or future models with smaller contexts. Users are recommended * to use practical values (e.g., 2048+). * [S1-004] vibe-local specific constant. If more vibe-local constants are added, * consider extracting to src/lib/cli-tools/vibe-local-config.ts. * [SEC-002] Used to prevent unreasonable values in CLI arguments. */ export declare const VIBE_LOCAL_CONTEXT_WINDOW_MIN = 128; /** * Maximum context window size for vibe-local (2M tokens). * Shared between API validation and defense-in-depth (DRY principle). * [S1-004] vibe-local specific constant. If more vibe-local constants are added, * consider extracting to src/lib/cli-tools/vibe-local-config.ts. * [SEC-002] Used to prevent unreasonable values in CLI arguments. */ export declare const VIBE_LOCAL_CONTEXT_WINDOW_MAX = 2097152; /** * Validate vibe-local context window value. * Shared between API layer and CLI layer (defense-in-depth). * [S1-001] DRY: Single source of truth for context window validation. * * @param value - Value to validate (accepts unknown for type guard usage) * @returns True if value is a valid context window size (integer between MIN and MAX) */ export declare function isValidVibeLocalContextWindow(value: unknown): value is number; /** * Ollama model name validation pattern (API/DB layer). * Requires alphanumeric first character, followed by alphanumeric, dots, underscores, * colons, slashes, hyphens. No explicit length limit (DB schema handles storage limits). * * [SEC-001] Shared between API route validation and CLI command construction. * * Note: opencode-config.ts has a separate OLLAMA_MODEL_PATTERN with a 100-character * length limit (`{1,100}`) for DoS protection when parsing Ollama API responses. * The patterns are intentionally different: this one enforces first-character constraints * for user-facing validation, while the opencode-config version adds length limits * for untrusted external API data. */ export declare const OLLAMA_MODEL_PATTERN: RegExp; /** * Image-capable CLI tool interface (ISP compliant) * Issue #474: Extends ICLITool with image sending capability * [S1-M1] Separated from ICLITool to follow Interface Segregation Principle */ export interface IImageCapableCLITool extends ICLITool { /** Returns true to indicate image support */ supportsImage(): true; /** * Send a message with an attached image * @param worktreeId - Worktree ID * @param message - Message text * @param imagePath - Absolute path to the image file * @param instanceId - Agent instance ID (Issue #868). Defaults to the primary instance. */ sendMessageWithImage(worktreeId: string, message: string, imagePath: string, instanceId?: string): Promise; } /** * Type guard to check if a CLI tool supports image sending * Issue #474: Used by send/route.ts to determine sending strategy * * @param tool - CLI tool instance to check * @returns True if the tool implements IImageCapableCLITool */ export declare function isImageCapableCLITool(tool: ICLITool): tool is IImageCapableCLITool; /** * CLIツール情報 */ export interface CLIToolInfo { /** CLIツールID */ id: CLIToolType; /** 表示名 */ name: string; /** コマンド名 */ command: string; /** インストール済みか */ installed: boolean; } //# sourceMappingURL=types.d.ts.map